| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| node-npmtest-marko/ | 100% | (153 / 153) | 100% | (126 / 126) | 100% | (28 / 28) | 100% | (153 / 153) | |
| node-npmtest-marko/node_modules/marko/ | 28.3% | (60 / 212) | 11.93% | (13 / 109) | 12% | (3 / 25) | 28.3% | (60 / 212) | |
| node-npmtest-marko/node_modules/marko/bin/ | 30.64% | (53 / 173) | 14.95% | (16 / 107) | 13.64% | (3 / 22) | 30.64% | (53 / 173) | |
| node-npmtest-marko/node_modules/marko/browser-refresh/ | 38.46% | (5 / 13) | 25% | (1 / 4) | 50% | (1 / 2) | 38.46% | (5 / 13) | |
| node-npmtest-marko/node_modules/marko/compiler/ | 14.81% | (233 / 1573) | 1.78% | (13 / 729) | 2.47% | (6 / 243) | 14.83% | (233 / 1571) | |
| node-npmtest-marko/node_modules/marko/compiler/ast/ | 8.75% | (173 / 1978) | 0.12% | (1 / 814) | 0.96% | (3 / 314) | 8.75% | (173 / 1978) | |
| node-npmtest-marko/node_modules/marko/compiler/ast/HtmlAttribute/ | 28.95% | (11 / 38) | 0% | (0 / 12) | 0% | (0 / 11) | 28.95% | (11 / 38) | |
| node-npmtest-marko/node_modules/marko/compiler/ast/HtmlAttribute/html/ | 14.67% | (11 / 75) | 0% | (0 / 48) | 0% | (0 / 8) | 14.67% | (11 / 75) | |
| node-npmtest-marko/node_modules/marko/compiler/ast/HtmlAttribute/vdom/ | 5.88% | (1 / 17) | 0% | (0 / 10) | 0% | (0 / 1) | 5.88% | (1 / 17) | |
| node-npmtest-marko/node_modules/marko/compiler/ast/HtmlElement/ | 9.57% | (9 / 94) | 0% | (0 / 48) | 0% | (0 / 25) | 9.57% | (9 / 94) | |
| node-npmtest-marko/node_modules/marko/compiler/ast/HtmlElement/html/ | 9.46% | (7 / 74) | 0% | (0 / 28) | 0% | (0 / 6) | 9.46% | (7 / 74) | |
| node-npmtest-marko/node_modules/marko/compiler/ast/HtmlElement/vdom/ | 7.48% | (16 / 214) | 0% | (0 / 129) | 0% | (0 / 11) | 7.48% | (16 / 214) | |
| node-npmtest-marko/node_modules/marko/compiler/ast/Text/ | 33.33% | (7 / 21) | 0% | (0 / 5) | 0% | (0 / 6) | 33.33% | (7 / 21) | |
| node-npmtest-marko/node_modules/marko/compiler/ast/Text/html/ | 12.5% | (4 / 32) | 0% | (0 / 20) | 0% | (0 / 2) | 12.5% | (4 / 32) | |
| node-npmtest-marko/node_modules/marko/compiler/ast/Text/vdom/ | 12.33% | (9 / 73) | 0% | (0 / 38) | 0% | (0 / 7) | 12.33% | (9 / 73) | |
| node-npmtest-marko/node_modules/marko/compiler/taglib-finder/ | 25.53% | (24 / 94) | 0% | (0 / 37) | 0% | (0 / 10) | 25.53% | (24 / 94) | |
| node-npmtest-marko/node_modules/marko/compiler/taglib-loader/ | 49.66% | (434 / 874) | 24.68% | (77 / 312) | 47.65% | (71 / 149) | 49.89% | (434 / 870) | |
| node-npmtest-marko/node_modules/marko/compiler/taglib-lookup/ | 13.48% | (31 / 230) | 0.8% | (1 / 125) | 3.23% | (1 / 31) | 13.48% | (31 / 230) | |
| node-npmtest-marko/node_modules/marko/compiler/util/ | 16.33% | (65 / 398) | 0% | (0 / 197) | 2.63% | (1 / 38) | 16.33% | (65 / 398) | |
| node-npmtest-marko/node_modules/marko/compiler/util/vdom/ | 22% | (22 / 100) | 0% | (0 / 36) | 0% | (0 / 14) | 22% | (22 / 100) | |
| node-npmtest-marko/node_modules/marko/components/ | 17.52% | (199 / 1136) | 0.22% | (1 / 460) | 1.34% | (2 / 149) | 17.55% | (199 / 1134) | |
| node-npmtest-marko/node_modules/marko/components/legacy/ | 12.2% | (35 / 287) | 0% | (0 / 171) | 0% | (0 / 26) | 12.46% | (35 / 281) | |
| node-npmtest-marko/node_modules/marko/components/taglib/ | 19.75% | (31 / 157) | 0% | (0 / 78) | 0% | (0 / 15) | 19.75% | (31 / 157) | |
| node-npmtest-marko/node_modules/marko/components/taglib/TransformHelper/ | 8.51% | (59 / 693) | 0% | (0 / 329) | 1.61% | (1 / 62) | 8.51% | (59 / 693) | |
| node-npmtest-marko/node_modules/marko/components/taglib/helpers/ | 28.57% | (6 / 21) | 0% | (0 / 4) | 0% | (0 / 7) | 28.57% | (6 / 21) | |
| node-npmtest-marko/node_modules/marko/components/taglib/util/ | 21.88% | (7 / 32) | 0% | (0 / 10) | 0% | (0 / 2) | 21.88% | (7 / 32) | |
| node-npmtest-marko/node_modules/marko/helpers/ | 27.27% | (3 / 11) | 0% | (0 / 6) | 0% | (0 / 2) | 27.27% | (3 / 11) | |
| node-npmtest-marko/node_modules/marko/morphdom/ | 7.89% | (15 / 190) | 0.82% | (1 / 122) | 0% | (0 / 11) | 7.94% | (15 / 189) | |
| node-npmtest-marko/node_modules/marko/runtime/ | 21.81% | (77 / 353) | 5.3% | (8 / 151) | 5.88% | (4 / 68) | 21.81% | (77 / 353) | |
| node-npmtest-marko/node_modules/marko/runtime/dependencies/ | 27.59% | (16 / 58) | 5.13% | (2 / 39) | 16.67% | (1 / 6) | 28.07% | (16 / 57) | |
| node-npmtest-marko/node_modules/marko/runtime/html/ | 21.87% | (89 / 407) | 1.64% | (3 / 183) | 0% | (0 / 63) | 21.87% | (89 / 407) | |
| node-npmtest-marko/node_modules/marko/runtime/loader/ | 21.52% | (17 / 79) | 2.44% | (1 / 41) | 0% | (0 / 10) | 21.52% | (17 / 79) | |
| node-npmtest-marko/node_modules/marko/runtime/vdom/ | 22.96% | (121 / 527) | 2.64% | (6 / 227) | 3.85% | (3 / 78) | 22.96% | (121 / 527) | |
| node-npmtest-marko/node_modules/marko/taglibs/async/ | 8.79% | (24 / 273) | 0% | (0 / 146) | 0% | (0 / 22) | 8.82% | (24 / 272) | |
| node-npmtest-marko/node_modules/marko/taglibs/cache/ | 14.89% | (7 / 47) | 0% | (0 / 20) | 0% | (0 / 9) | 14.89% | (7 / 47) | |
| node-npmtest-marko/node_modules/marko/taglibs/core/ | 9.73% | (40 / 411) | 0% | (0 / 156) | 2.7% | (1 / 37) | 9.73% | (40 / 411) | |
| node-npmtest-marko/node_modules/marko/taglibs/core/util/ | 9.52% | (22 / 231) | 0% | (0 / 141) | 0% | (0 / 14) | 9.61% | (22 / 229) | |
| node-npmtest-marko/node_modules/marko/taglibs/html/ | 16.67% | (1 / 6) | 0% | (0 / 4) | 0% | (0 / 1) | 16.67% | (1 / 6) | |
| node-npmtest-marko/node_modules/marko/taglibs/layout/ | 10.53% | (4 / 38) | 0% | (0 / 10) | 0% | (0 / 3) | 10.53% | (4 / 38) |
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| example.js | 100% | (83 / 83) | 100% | (73 / 73) | 100% | (12 / 12) | 100% | (83 / 83) | |
| lib.npmtest_marko.js | 100% | (16 / 16) | 100% | (14 / 14) | 100% | (3 / 3) | 100% | (16 / 16) | |
| test.js | 100% | (54 / 54) | 100% | (39 / 39) | 100% | (13 / 13) | 100% | (54 / 54) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | 2 2 2 2 2 2 2 1 2 2 2 2 1 2 2 2 2 2 1 2 1 1 1 1 1 1 1 1 1 2 1 1 1 1 2 2 3 3 3 3 1 3 3 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 6 6 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | /*
example.js
quickstart example
instruction
1. save this script as example.js
2. run the shell command:
$ npm install npmtest-marko && PORT=8081 node example.js
3. play with the browser-demo on http://127.0.0.1:8081
*/
/* istanbul instrument in package npmtest_marko */
/*jslint
bitwise: true,
browser: true,
maxerr: 8,
maxlen: 96,
node: true,
nomen: true,
regexp: true,
stupid: true
*/
(function () {
'use strict';
var local;
// run shared js-env code - init-before
(function () {
// init local
local = {};
// init modeJs
local.modeJs = (function () {
try {
return typeof navigator.userAgent === 'string' &&
typeof document.querySelector('body') === 'object' &&
typeof XMLHttpRequest.prototype.open === 'function' &&
'browser';
} catch (errorCaughtBrowser) {
return module.exports &&
typeof process.versions.node === 'string' &&
typeof require('http').createServer === 'function' &&
'node';
}
}());
// init global
local.global = local.modeJs === 'browser'
? window
: global;
// init utility2_rollup
local = local.global.utility2_rollup || (local.modeJs === 'browser'
? local.global.utility2_npmtest_marko
: global.utility2_moduleExports);
// export local
local.global.local = local;
}());
switch (local.modeJs) {
// init-after
// run browser js-env code - init-after
/* istanbul ignore next */
case 'browser':
local.testRunBrowser = function (event) {
Eif (!event || (event &&
event.currentTarget &&
event.currentTarget.className &&
event.currentTarget.className.includes &&
event.currentTarget.className.includes('onreset'))) {
// reset output
Array.from(
document.querySelectorAll('body > .resettable')
).forEach(function (element) {
switch (element.tagName) {
case 'INPUT':
case 'TEXTAREA':
element.value = '';
break;
default:
element.textContent = '';
}
});
}
switch (event && event.currentTarget && event.currentTarget.id) {
case 'testRunButton1':
// show tests
Eif (document.querySelector('#testReportDiv1').style.display === 'none') {
document.querySelector('#testReportDiv1').style.display = 'block';
document.querySelector('#testRunButton1').textContent =
'hide internal test';
local.modeTest = true;
local.testRunDefault(local);
// hide tests
} else {
document.querySelector('#testReportDiv1').style.display = 'none';
document.querySelector('#testRunButton1').textContent = 'run internal test';
}
break;
// custom-case
default:
break;
}
Iif (document.querySelector('#inputTextareaEval1') && (!event || (event &&
event.currentTarget &&
event.currentTarget.className &&
event.currentTarget.className.includes &&
event.currentTarget.className.includes('oneval')))) {
// try to eval input-code
try {
/*jslint evil: true*/
eval(document.querySelector('#inputTextareaEval1').value);
} catch (errorCaught) {
console.error(errorCaught);
}
}
};
// log stderr and stdout to #outputTextareaStdout1
['error', 'log'].forEach(function (key) {
console[key + '_original'] = console[key];
console[key] = function () {
var element;
console[key + '_original'].apply(console, arguments);
element = document.querySelector('#outputTextareaStdout1');
Iif (!element) {
return;
}
// append text to #outputTextareaStdout1
element.value += Array.from(arguments).map(function (arg) {
return typeof arg === 'string'
? arg
: JSON.stringify(arg, null, 4);
}).join(' ') + '\n';
// scroll textarea to bottom
element.scrollTop = element.scrollHeight;
};
});
// init event-handling
['change', 'click', 'keyup'].forEach(function (event) {
Array.from(document.querySelectorAll('.on' + event)).forEach(function (element) {
element.addEventListener(event, local.testRunBrowser);
});
});
// run tests
local.testRunBrowser();
break;
// run node js-env code - init-after
/* istanbul ignore next */
case 'node':
// export local
module.exports = local;
// require modules
local.fs = require('fs');
local.http = require('http');
local.url = require('url');
// init assets
local.assetsDict = local.assetsDict || {};
/* jslint-ignore-begin */
local.assetsDict['/assets.index.template.html'] = '\
<!doctype html>\n\
<html lang="en">\n\
<head>\n\
<meta charset="UTF-8">\n\
<meta name="viewport" content="width=device-width, initial-scale=1">\n\
<title>{{env.npm_package_name}} (v{{env.npm_package_version}})</title>\n\
<style>\n\
/*csslint\n\
box-sizing: false,\n\
universal-selector: false\n\
*/\n\
* {\n\
box-sizing: border-box;\n\
}\n\
body {\n\
background: #dde;\n\
font-family: Arial, Helvetica, sans-serif;\n\
margin: 2rem;\n\
}\n\
body > * {\n\
margin-bottom: 1rem;\n\
}\n\
.utility2FooterDiv {\n\
margin-top: 20px;\n\
text-align: center;\n\
}\n\
</style>\n\
<style>\n\
/*csslint\n\
*/\n\
textarea {\n\
font-family: monospace;\n\
height: 10rem;\n\
width: 100%;\n\
}\n\
textarea[readonly] {\n\
background: #ddd;\n\
}\n\
</style>\n\
</head>\n\
<body>\n\
<!-- utility2-comment\n\
<div id="ajaxProgressDiv1" style="background: #d00; height: 2px; left: 0; margin: 0; padding: 0; position: fixed; top: 0; transition: background 0.5s, width 1.5s; width: 25%;"></div>\n\
utility2-comment -->\n\
<h1>\n\
<!-- utility2-comment\n\
<a\n\
{{#if env.npm_package_homepage}}\n\
href="{{env.npm_package_homepage}}"\n\
{{/if env.npm_package_homepage}}\n\
target="_blank"\n\
>\n\
utility2-comment -->\n\
{{env.npm_package_name}} (v{{env.npm_package_version}})\n\
<!-- utility2-comment\n\
</a>\n\
utility2-comment -->\n\
</h1>\n\
<h3>{{env.npm_package_description}}</h3>\n\
<!-- utility2-comment\n\
<h4><a download href="assets.app.js">download standalone app</a></h4>\n\
<button class="onclick onreset" id="testRunButton1">run internal test</button><br>\n\
<div id="testReportDiv1" style="display: none;"></div>\n\
utility2-comment -->\n\
\n\
\n\
\n\
<label>stderr and stdout</label>\n\
<textarea class="resettable" id="outputTextareaStdout1" readonly></textarea>\n\
<!-- utility2-comment\n\
{{#if isRollup}}\n\
<script src="assets.app.js"></script>\n\
{{#unless isRollup}}\n\
utility2-comment -->\n\
<script src="assets.utility2.rollup.js"></script>\n\
<script src="jsonp.utility2._stateInit?callback=window.utility2._stateInit"></script>\n\
<script src="assets.npmtest_marko.rollup.js"></script>\n\
<script src="assets.example.js"></script>\n\
<script src="assets.test.js"></script>\n\
<!-- utility2-comment\n\
{{/if isRollup}}\n\
utility2-comment -->\n\
<div class="utility2FooterDiv">\n\
[ this app was created with\n\
<a href="https://github.com/kaizhu256/node-utility2" target="_blank">utility2</a>\n\
]\n\
</div>\n\
</body>\n\
</html>\n\
';
/* jslint-ignore-end */
Iif (local.templateRender) {
local.assetsDict['/'] = local.templateRender(
local.assetsDict['/assets.index.template.html'],
{
env: local.objectSetDefault(local.env, {
npm_package_description: 'the greatest app in the world!',
npm_package_name: 'my-app',
npm_package_nameAlias: 'my_app',
npm_package_version: '0.0.1'
})
}
);
} else {
local.assetsDict['/'] = local.assetsDict['/assets.index.template.html']
.replace((/\{\{env\.(\w+?)\}\}/g), function (match0, match1) {
// jslint-hack
String(match0);
switch (match1) {
case 'npm_package_description':
return 'the greatest app in the world!';
case 'npm_package_name':
return 'my-app';
case 'npm_package_nameAlias':
return 'my_app';
case 'npm_package_version':
return '0.0.1';
}
});
}
// run the cli
Eif (local.global.utility2_rollup || module !== require.main) {
break;
}
local.assetsDict['/assets.example.js'] =
local.assetsDict['/assets.example.js'] ||
local.fs.readFileSync(__filename, 'utf8');
// bug-workaround - long $npm_package_buildCustomOrg
/* jslint-ignore-begin */
local.assetsDict['/assets.npmtest_marko.rollup.js'] =
local.assetsDict['/assets.npmtest_marko.rollup.js'] ||
local.fs.readFileSync(
local.npmtest_marko.__dirname + '/lib.npmtest_marko.js',
'utf8'
).replace((/^#!/), '//');
/* jslint-ignore-end */
local.assetsDict['/favicon.ico'] = local.assetsDict['/favicon.ico'] || '';
// if $npm_config_timeout_exit exists,
// then exit this process after $npm_config_timeout_exit ms
if (Number(process.env.npm_config_timeout_exit)) {
setTimeout(process.exit, Number(process.env.npm_config_timeout_exit));
}
// start server
if (local.global.utility2_serverHttp1) {
break;
}
process.env.PORT = process.env.PORT || '8081';
console.error('server starting on port ' + process.env.PORT);
local.http.createServer(function (request, response) {
request.urlParsed = local.url.parse(request.url);
if (local.assetsDict[request.urlParsed.pathname] !== undefined) {
response.end(local.assetsDict[request.urlParsed.pathname]);
return;
}
response.statusCode = 404;
response.end();
}).listen(process.env.PORT);
break;
}
}());
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 2 2 2 2 2 2 2 1 2 2 2 2 1 1 1 1 | /* istanbul instrument in package npmtest_marko */
/*jslint
bitwise: true,
browser: true,
maxerr: 8,
maxlen: 96,
node: true,
nomen: true,
regexp: true,
stupid: true
*/
(function () {
'use strict';
var local;
// run shared js-env code - init-before
(function () {
// init local
local = {};
// init modeJs
local.modeJs = (function () {
try {
return typeof navigator.userAgent === 'string' &&
typeof document.querySelector('body') === 'object' &&
typeof XMLHttpRequest.prototype.open === 'function' &&
'browser';
} catch (errorCaughtBrowser) {
return module.exports &&
typeof process.versions.node === 'string' &&
typeof require('http').createServer === 'function' &&
'node';
}
}());
// init global
local.global = local.modeJs === 'browser'
? window
: global;
// init utility2_rollup
local = local.global.utility2_rollup || local;
// init lib
local.local = local.npmtest_marko = local;
// init exports
if (local.modeJs === 'browser') {
local.global.utility2_npmtest_marko = local;
} else {
module.exports = local;
module.exports.__dirname = __dirname;
module.exports.module = module;
}
}());
}());
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | 2 2 2 2 2 2 2 1 2 2 1 1 1 1 2 2 2 2 1 1 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 1 2 2 1 2 2 1 2 2 1 1 1 1 1 | /* istanbul instrument in package npmtest_marko */
/*jslint
bitwise: true,
browser: true,
maxerr: 8,
maxlen: 96,
node: true,
nomen: true,
regexp: true,
stupid: true
*/
(function () {
'use strict';
var local;
// run shared js-env code - init-before
(function () {
// init local
local = {};
// init modeJs
local.modeJs = (function () {
try {
return typeof navigator.userAgent === 'string' &&
typeof document.querySelector('body') === 'object' &&
typeof XMLHttpRequest.prototype.open === 'function' &&
'browser';
} catch (errorCaughtBrowser) {
return module.exports &&
typeof process.versions.node === 'string' &&
typeof require('http').createServer === 'function' &&
'node';
}
}());
// init global
local.global = local.modeJs === 'browser'
? window
: global;
switch (local.modeJs) {
// re-init local from window.local
case 'browser':
local = local.global.utility2.objectSetDefault(
local.global.utility2_rollup || local.global.local,
local.global.utility2
);
break;
// re-init local from example.js
case 'node':
local = (local.global.utility2_rollup || require('utility2'))
.requireReadme();
break;
}
// export local
local.global.local = local;
}());
// run shared js-env code - function
(function () {
return;
}());
switch (local.modeJs) {
// run browser js-env code - function
case 'browser':
break;
// run node js-env code - function
case 'node':
break;
}
// run shared js-env code - init-after
(function () {
return;
}());
switch (local.modeJs) {
// run browser js-env code - init-after
case 'browser':
local.testCase_browser_nullCase = local.testCase_browser_nullCase || function (
options,
onError
) {
/*
* this function will test browsers's null-case handling-behavior-behavior
*/
onError(null, options);
};
// run tests
local.nop(local.modeTest &&
document.querySelector('#testRunButton1') &&
document.querySelector('#testRunButton1').click());
break;
// run node js-env code - init-after
/* istanbul ignore next */
case 'node':
local.testCase_buildApidoc_default = local.testCase_buildApidoc_default || function (
options,
onError
) {
/*
* this function will test buildApidoc's default handling-behavior-behavior
*/
options = { modulePathList: module.paths };
local.buildApidoc(options, onError);
};
local.testCase_buildApp_default = local.testCase_buildApp_default || function (
options,
onError
) {
/*
* this function will test buildApp's default handling-behavior-behavior
*/
local.testCase_buildReadme_default(options, local.onErrorThrow);
local.testCase_buildLib_default(options, local.onErrorThrow);
local.testCase_buildTest_default(options, local.onErrorThrow);
local.testCase_buildCustomOrg_default(options, local.onErrorThrow);
options = [];
local.buildApp(options, onError);
};
local.testCase_buildCustomOrg_default = local.testCase_buildCustomOrg_default ||
function (options, onError) {
/*
* this function will test buildCustomOrg's default handling-behavior
*/
options = {};
local.buildCustomOrg(options, onError);
};
local.testCase_buildLib_default = local.testCase_buildLib_default || function (
options,
onError
) {
/*
* this function will test buildLib's default handling-behavior
*/
options = {};
local.buildLib(options, onError);
};
local.testCase_buildReadme_default = local.testCase_buildReadme_default || function (
options,
onError
) {
/*
* this function will test buildReadme's default handling-behavior-behavior
*/
options = {};
local.buildReadme(options, onError);
};
local.testCase_buildTest_default = local.testCase_buildTest_default || function (
options,
onError
) {
/*
* this function will test buildTest's default handling-behavior
*/
options = {};
local.buildTest(options, onError);
};
local.testCase_webpage_default = local.testCase_webpage_default || function (
options,
onError
) {
/*
* this function will test webpage's default handling-behavior
*/
options = { modeCoverageMerge: true, url: local.serverLocalHost + '?modeTest=1' };
local.browserTest(options, onError);
};
// run test-server
local.testRunServer(local);
break;
}
}());
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| defineRenderer.js | 12.5% | (3 / 24) | 0% | (0 / 12) | 0% | (0 / 3) | 12.5% | (3 / 24) | |
| express.js | 16.67% | (4 / 24) | 0% | (0 / 6) | 0% | (0 / 4) | 16.67% | (4 / 24) | |
| html.js | 100% | (1 / 1) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (1 / 1) | |
| jquery.js | 16.13% | (5 / 31) | 4.17% | (1 / 24) | 33.33% | (1 / 3) | 16.13% | (5 / 31) | |
| node-require-browser.js | 100% | (1 / 1) | 100% | (0 / 0) | 0% | (0 / 1) | 100% | (1 / 1) | |
| node-require.js | 43.66% | (31 / 71) | 29.41% | (10 / 34) | 33.33% | (2 / 6) | 43.66% | (31 / 71) | |
| ready.js | 22.41% | (13 / 58) | 6.06% | (2 / 33) | 0% | (0 / 8) | 22.41% | (13 / 58) | |
| stream.js | 100% | (1 / 1) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (1 / 1) | |
| vdom.js | 100% | (1 / 1) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (1 / 1) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 1 1 1 | var marko = require('./');
function defineRenderer(def) {
var template = def.template;
var getTemplateData = def.getTemplateData;
var renderer = def.renderer;
if (typeof template === 'string') {
template = marko.load(template);
}
var createOut;
if (template) {
createOut = template.createOut;
} else {
createOut = def.createOut || marko.createOut;
}
if (!renderer) {
// Create a renderer function that takes care of translating
// the input properties to a view state. Also, this renderer
// takes care of re-using existing components.
renderer = function renderer(input, out) {
var newProps = input;
if (!newProps) {
// Make sure we always have a non-null input object
newProps = {};
}
// Use getTemplateData(state, props, out) to get the template
// data. If that method is not provided then just use the
// the state (if provided) or the input data.
var templateData = getTemplateData ?
getTemplateData(newProps, out) :
newProps;
// Render the template associated with the component using the final template
// data that we constructed
template.render(templateData, out);
};
}
renderer.render = function(input) {
var out = createOut();
renderer(input, out);
return out.end();
};
return renderer;
}
module.exports = defineRenderer;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 2 2 2 1 | require('./runtime/env-init');
var assign = require('object-assign');
var express = module.parent.require('express');
patchResponse(express.response);
delete require.cache[__filename];
module.exports = function markoAppMiddleware() {
var sacrificialApp = express();
sacrificialApp.once('mount', function onmount(parent) {
// Patch the response
patchResponse(parent.response);
// Remove sacrificial express app
parent._router.stack.pop();
});
return sacrificialApp;
}
function patchResponse(response) {
response.marko = response.marko || function(template, data) {
if(typeof template === 'string') {
throw new Error(
'res.marko does not take a template name or path like res.render. ' +
'Instead you should use `require(\'./path/to/template.marko\')` ' +
'and pass the loaded template to this function.'
);
}
var res = this;
var req = res.req;
var app = res.app;
var $global = assign({ app, req, res }, app.locals, res.locals);
if (data) {
data = assign(data, {
$global: assign($global, data.$global)
});
} else {
data = { $global };
}
res.set({ 'content-type': 'text/html; charset=utf-8' });
template.render(data, res);
};
}
|
| 1 2 | 1 | module.exports = require('./runtime/html');
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | 1 1 1 2 2 | var ready = require('./ready');
var idRegExp = /^\#(\S+)( .*)?/;
exports.patchComponent = function(jQuery) {
/* globals window */
Eif (!jQuery) {
jQuery = window.$;
if (!jQuery) {
throw new Error('jQuery not found');
}
}
require('./components/Component').prototype.$ = function jqueryProxy(arg) {
var args = arguments;
var self = this;
if (args.length === 1) {
//Handle an "ondomready" callback function
if (typeof arg === 'function') {
return ready(function() {
arg.call(self);
});
} else if (typeof arg === 'string') {
var match = idRegExp.exec(arg);
//Reset the search to 0 so the next call to exec will start from the beginning for the new string
if (match != null) {
var componentElId = match[1];
if (match[2] == null) {
return jQuery(self.getEl(componentElId));
} else {
return jQuery('#' + self.getElId(componentElId) + match[2]);
}
} else {
var rootEl = self.getEl();
if (!rootEl) {
throw new Error('Root element is not defined for component');
}
if (rootEl) {
return jQuery(arg, rootEl);
}
}
}
} else if (args.length === 2 && typeof args[1] === 'string') {
return jQuery(arg, self.getEl(args[1]));
} else if (args.length === 0) {
return jQuery(self.el);
}
return jQuery.apply(window, arguments);
};
};
|
| 1 2 | 1 | exports.install = function() {};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
require('./runtime/env-init');
const path = require('path');
const resolveFrom = require('resolve-from');
const fs = require('fs');
const fsReadOptions = { encoding: 'utf8' };
const MARKO_EXTENSIONS = Symbol('MARKO_EXTENSIONS');
function normalizeExtension(extension) {
Iif (extension.charAt(0) !== '.') {
extension = '.' + extension;
}
return extension;
}
function compile(templatePath, markoCompiler, compilerOptions) {
if (compilerOptions) {
compilerOptions = Object.assign({}, markoCompiler.defaultOptions, compilerOptions);
} else {
compilerOptions = markoCompiler.defaultOptions;
}
var writeToDisk = compilerOptions.writeToDisk;
var templateSrc;
var compiledSrc;
if (writeToDisk === false) {
// Don't write the compiled template to disk. Instead, load it
// directly from the compiled source using the internals of the
// Node.js module loading system.
templateSrc = fs.readFileSync(templatePath, fsReadOptions);
compiledSrc = markoCompiler.compile(templateSrc, templatePath);
} else {
var targetFile = templatePath + '.js';
if (markoCompiler.defaultOptions.assumeUpToDate && fs.existsSync(targetFile)) {
// If the target file already exists and "assumeUpToDate" then just use the previously
// compiled template.
return fs.readFileSync(targetFile, fsReadOptions);
}
var targetDir = path.dirname(templatePath);
var isUpToDate = markoCompiler.checkUpToDate(targetFile);
if (isUpToDate) {
compiledSrc = fs.readFileSync(targetFile, fsReadOptions);
} else {
templateSrc = fs.readFileSync(templatePath, fsReadOptions);
compiledSrc = markoCompiler.compile(templateSrc, templatePath, compilerOptions);
// Write to a temporary file and move it into place to avoid problems
// assocatiated with multiple processes write to the same file. We only
// write the compiled source code to disk so that stack traces will
// be accurate.
var filename = path.basename(targetFile);
var tempFile = path.join(targetDir, '.' + process.pid + '.' + Date.now() + '.' + filename);
fs.writeFileSync(tempFile, compiledSrc, fsReadOptions);
fs.renameSync(tempFile, targetFile);
}
}
// We attach a path to the compiled template so that hot reloading will work.
return compiledSrc;
}
function getLoadedTemplate(path) {
var cached = require.cache[path];
return cached && cached.exports.render ? cached.exports : undefined;
}
function install(options) {
options = options || {};
var requireExtensions = options.require ? // options.require introduced for testing
options.require.extensions :
require.extensions;
var compilerOptions = options.compilerOptions;
Iif (compilerOptions) {
require('./compiler').configure(compilerOptions);
} else {
compilerOptions = {};
}
var extensions = [];
Iif (options.extension) {
extensions.push(options.extension);
}
Iif (options.extensions) {
extensions = extensions.concat(options.extensions);
}
Eif (extensions.length === 0) {
extensions.push('.marko');
}
function markoRequireExtension(module, filename) {
var targetFile = filename + '.js';
var cachedTemplate = getLoadedTemplate(targetFile) || getLoadedTemplate(filename);
if (cachedTemplate) {
// The template has already been loaded so use the exports of the already loaded template
module.exports = cachedTemplate;
return;
}
// Resolve the appropriate compiler relative to the location of the
// marko template file on disk using the "resolve-from" module.
var dirname = path.dirname(filename);
var markoCompilerModulePath = resolveFrom(dirname, 'marko/compiler');
var markoCompiler = require(markoCompilerModulePath);
// Now use the appropriate Marko compiler to compile the Marko template
// file to JavaScript source code:
var compiledSrc = compile(filename, markoCompiler, compilerOptions);
// Append ".js" to the filename since that is where we write the compiled
// source code that is being loaded. This allows stack traces to match up.
module._compile(compiledSrc, targetFile);
}
requireExtensions[MARKO_EXTENSIONS] = requireExtensions[MARKO_EXTENSIONS] ||
(requireExtensions[MARKO_EXTENSIONS] = []);
extensions.forEach((extension) => {
extension = normalizeExtension(extension);
requireExtensions[extension] = markoRequireExtension;
requireExtensions[MARKO_EXTENSIONS].push(extension);
});
}
install();
exports.install = install;
exports.getExtensions = function() {
return require.extensions[MARKO_EXTENSIONS];
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | /*
jQuery's doc.ready/$(function(){}) should
you wish to use a cross-browser domReady solution
without opting for a library.
Demo: http://jsfiddle.net/zKLpb/
usage:
$(function(){
// your code
});
Parts: jQuery project, Diego Perini, Lucent M.
Previous version from Addy Osmani (https://raw.github.com/addyosmani/jquery.parts/master/jquery.documentReady.js)
This version: Patrick Steele-Idem
- Converted to CommonJS module
- Code cleanup
- Fixes for IE <=10
*/
/* globals window */
var isReady = false;
var readyBound = false;
var defaultWindow = typeof window != 'undefined' && window;
var defaultDocument = typeof document != 'undefined' && document;
var listeners = [];
function domReadyCallback() {
for (var i = 0, len = listeners.length; i < len; i++) {
var listener = listeners[i];
listener[0].call(listener[1]);
}
listeners = null;
}
function bindReady(doc) {
var toplevel = false;
var win = doc.defaultView || defaultWindow || doc;
// Handle when the DOM is ready
function domReady() {
// Make sure that the DOM is not already loaded
if (!isReady) {
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
if (!doc.body) {
return setTimeout(domReady, 1);
}
// Remember that the DOM is ready
isReady = true;
// If there are functions bound, to execute
domReadyCallback();
// Execute all of them
}
} // /ready()
// The ready event handler
function domContentLoaded() {
if (doc.addEventListener) {
doc.removeEventListener("DOMContentLoaded", domContentLoaded, false);
doc.removeEventListener("load", domContentLoaded, false);
} else {
// we're here because readyState !== "loading" in oldIE
// which is good enough for us to call the dom ready!
doc.detachEvent("onreadystatechange", domContentLoaded);
doc.detachEvent("onload", domContentLoaded);
}
domReady();
}
// The DOM ready check for Internet Explorer
function doScrollCheck() {
if (isReady) {
return;
}
try {
// If IE is used, use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
doc.documentElement.doScroll("left");
} catch (error) {
setTimeout(doScrollCheck, 1);
return;
}
// and execute any waiting functions
domReady();
}
// Catch cases where $ is called after the
// browser event has already occurred. IE <= 10 has a bug that results in 'interactive' being assigned
// to the readyState before the DOM is really ready
if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") {
// We will get here if the browser is IE and the readyState === 'complete' or the browser
// is not IE and the readyState === 'interactive' || 'complete'
domReady(doc);
} else if (doc.addEventListener) { // Standards-based browsers support DOMContentLoaded
// Use the handy event callback
doc.addEventListener("DOMContentLoaded", domContentLoaded, false);
// A fallback to win.onload, that will always work
win.addEventListener("load", domContentLoaded, false);
// If IE event model is used
} else if (doc.attachEvent) {
// ensure firing before onload,
// maybe late but safe also for iframes
doc.attachEvent("onreadystatechange", domContentLoaded);
// A fallback to win.onload, that will always work
win.attachEvent("onload", domContentLoaded);
// If IE and not a frame
// continually check to see if the document is ready
try {
toplevel = win.frameElement == null;
} catch (e) {}
if (doc.documentElement.doScroll && toplevel) {
doScrollCheck();
}
}
}
function ready(callback, thisObj, doc) {
if (isReady) {
return callback.call(thisObj);
}
listeners.push([callback, thisObj]);
if (!readyBound) {
readyBound = true;
bindReady(doc || defaultDocument);
}
}
module.exports = ready;
module.exports.patchComponent = function() {
require('./components/Component').prototype.ready = function (callback) {
var document = this.el.ownerDocument;
ready(callback, this, document);
};
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | 1 | /*
This module is used to monkey patch `Template.prototype` to add a new `stream(templateData)` method. Since
streaming module is likely not needed in the browser, we have made this method optional.
Template.prototype.stream is always available on the server, but if you need streaming in the browser you must add
the following line to your app:
require('marko/stream');
*/
require('./runtime/stream');
|
| 1 2 | 1 | module.exports = require('./runtime/vdom');
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| markoc.js | 30.64% | (53 / 173) | 14.95% | (16 / 107) | 13.64% | (3 / 22) | 30.64% | (53 / 173) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 1 2 1 1 1 1 1 1 1 1 1 1 | var fs = require('fs');
var nodePath = require('path');
var cwd = process.cwd();
var resolveFrom = require('resolve-from');
// Try to use the Marko compiler installed with the project
var markoCompilerPath;
const markocPkgVersion = require('../package.json').version;
var markoPkgVersion;
try {
var markoPkgPath = resolveFrom(process.cwd(), 'marko/package.json');
markoPkgVersion = require(markoPkgPath).version;
} catch(e) {}
try {
markoCompilerPath = resolveFrom(process.cwd(), 'marko/compiler');
} catch(e) {}
var markoCompiler;
Eif (markoCompilerPath) {
markoCompiler = require(markoCompilerPath);
} else {
markoCompiler = require('../compiler');
}
var Minimatch = require('minimatch').Minimatch;
var appModulePath = require('app-module-path');
require('raptor-polyfill/string/startsWith');
require('raptor-polyfill/string/endsWith');
markoCompiler.defaultOptions.checkUpToDate = false;
var mmOptions = {
matchBase: true,
dot: true,
flipNegate: true
};
function relPath(path) {
if (path.startsWith(cwd)) {
return path.substring(cwd.length+1);
}
}
var args = require('argly').createParser({
'--help': {
type: 'boolean',
description: 'Show this help message'
},
'--files --file -f *': {
type: 'string[]',
description: 'A set of directories or files to compile'
},
'--ignore -i': {
type: 'string[]',
description: 'An ignore rule (default: --ignore "/node_modules" ".*")'
},
'--clean -c': {
type: 'boolean',
description: 'Clean all of the *.marko.js files'
},
'--force': {
type: 'boolean',
description: 'Force template recompilation even if unchanged'
},
'--paths -p': {
type: 'string[]',
description: 'Additional directories to add to the Node.js module search path'
},
'--vdom -V': {
type: 'boolean',
description: 'VDOM output'
},
'--version -v': {
type: 'boolean',
description: 'Print markoc and marko compiler versions to the console'
}
})
.usage('Usage: $0 <pattern> [options]')
.example('Compile a single template', '$0 template.marko')
.example('Compile all templates in the current directory', '$0 .')
.example('Compile multiple templates', '$0 template.marko src/ foo/')
.example('Delete all *.marko.js files in the current directory', '$0 . --clean')
.validate(function(result) {
Iif (result.help) {
this.printUsage();
process.exit(0);
} else Iif (result.version) {
console.log('markoc@' + markocPkgVersion);
if (markoPkgVersion) {
console.log('marko@' + markoPkgVersion);
}
process.exit(0);
} else Eif (!result.files || result.files.length === 0) {
this.printUsage();
process.exit(1);
}
})
.onError(function(err) {
this.printUsage();
if (err) {
console.log();
console.log(err);
}
process.exit(1);
})
.parse();
var output = 'html';
Iif (args.vdom) {
output = 'vdom';
}
var compileOptions = {
output: output,
compilerType: 'markoc',
compilerVersion: markoPkgVersion || markocPkgVersion
};
var force = args.force;
Iif (force) {
markoCompiler.defaultOptions.checkUpToDate = false;
}
var paths = args.paths;
Iif (paths && paths.length) {
paths.forEach(function(path) {
appModulePath.addPath(nodePath.resolve(cwd, path));
});
}
var ignoreRules = args.ignore;
Eif (!ignoreRules) {
ignoreRules = ['/node_modules', '.*'];
}
ignoreRules = ignoreRules.filter(function (s) {
s = s.trim();
return s && !s.match(/^#/);
});
ignoreRules = ignoreRules.map(function (pattern) {
return new Minimatch(pattern, mmOptions);
});
function isIgnored(path, dir, stat) {
if (path.startsWith(dir)) {
path = path.substring(dir.length);
}
path = path.replace(/\\/g, '/');
var ignore = false;
var ignoreRulesLength = ignoreRules.length;
for (var i=0; i<ignoreRulesLength; i++) {
var rule = ignoreRules[i];
var match = rule.match(path);
if (!match && stat && stat.isDirectory()) {
try {
stat = fs.statSync(path);
} catch(e) {}
if (stat && stat.isDirectory()) {
match = rule.match(path + '/');
}
}
if (match) {
if (rule.negate) {
ignore = false;
} else {
ignore = true;
}
}
}
return ignore;
}
function walk(files, options, done) {
if (!files || files.length === 0) {
done('No files provided');
}
var pending = 0;
if (!Array.isArray(files)) {
files = [files];
}
var fileCallback = options.file;
var context = {
errors: [],
beginAsync: function() {
pending++;
},
endAsync: function(err) {
if (err) {
this.errors.push(err);
}
pending--;
if (pending === 0) {
if (this.errors.length) {
done(this.errors);
} else {
done(null);
}
}
}
};
function doWalk(dir) {
context.beginAsync();
fs.readdir(dir, function(err, list) {
if (err) {
return context.endAsync(err);
}
if (list.length) {
list.forEach(function(basename) {
var file = nodePath.join(dir, basename);
context.beginAsync();
fs.stat(file, function(err, stat) {
if (err) {
return context.endAsync(err);
}
if (!isIgnored(file, dir, stat)) {
if (stat && stat.isDirectory()) {
doWalk(file);
} else {
fileCallback(file, context);
}
}
context.endAsync();
});
});
}
context.endAsync();
});
}
for (var i=0; i<files.length; i++) {
var file = nodePath.resolve(cwd, files[i]);
var stat = fs.statSync(file);
if (stat.isDirectory()) {
doWalk(file);
} else {
fileCallback(file, context);
}
}
}
Iif (args.clean) {
var deleteCount = 0;
walk(
args.files,
{
file: function(file, context) {
var basename = nodePath.basename(file);
if (basename.endsWith('.marko.js') || basename.endsWith('.marko.html') || basename.endsWith('.marko.xml.js')) {
context.beginAsync();
fs.unlink(file, function(err) {
if (err) {
return context.endAsync(err);
}
deleteCount++;
console.log('Deleted: ' + file);
context.endAsync();
});
}
}
},
function(err) {
if (deleteCount === 0) {
console.log('No *.marko.js files were found. Already clean.');
} else {
console.log('Deleted ' + deleteCount + ' file(s)');
}
});
} else {
var found = {};
var compileCount = 0;
var failed;
var failed = [];
var compile = function(path, context) {
if (found[path]) {
return;
}
found[path] = true;
var outPath = path + '.js';
console.log('Compiling:\n Input: ' + relPath(path) + '\n Output: ' + relPath(outPath) + '\n');
context.beginAsync();
markoCompiler.compileFile(path, compileOptions, function(err, src) {
if (err) {
failed.push('Failed to compile "' + relPath(path) + '". Error: ' + (err.stack || err));
context.endAsync(err);
return;
}
context.beginAsync();
fs.writeFile(outPath, src, {encoding: 'utf8'}, function(err, src) {
if (err) {
failed.push('Failed to write "' + path + '". Error: ' + (err.stack || err));
context.endAsync(err);
return;
}
compileCount++;
context.endAsync();
});
context.endAsync();
});
};
Iif (args.files && args.files.length) {
walk(
args.files,
{
file: function(file, context) {
var basename = nodePath.basename(file);
if (basename.endsWith('.marko') || basename.endsWith('.marko.html') || basename.endsWith('.marko.xml')) {
compile(file, context);
}
}
},
function(err) {
if (err) {
if (failed.length) {
console.error('The following errors occurred:\n- ' + failed.join('\n- '));
} else {
console.error(err);
}
return;
}
if (compileCount === 0) {
console.log('No templates found');
} else {
console.log('Compiled ' + compileCount + ' templates(s)');
}
});
}
}
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 38.46% | (5 / 13) | 25% | (1 / 4) | 50% | (1 / 2) | 38.46% | (5 / 13) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 1 1 1 1 1 | var enabled = false;
var browserRefreshClient = require('browser-refresh-client');
exports.enable = function() {
Eif (!browserRefreshClient.isBrowserRefreshEnabled()) {
return;
}
if (enabled) {
return;
}
enabled = true;
// We set an environment variable so that _all_ marko modules
// installed in the project will have browser refresh enabled.
process.env.MARKO_BROWSER_REFRESH = 'true';
var hotReload = require('../hot-reload');
hotReload.enable();
browserRefreshClient
.enableSpecialReload('*.marko marko.json marko-tag.json')
.onFileModified(function(path) {
hotReload.handleFileModified(path);
});
};
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| Builder.js | 20.77% | (65 / 313) | 0% | (0 / 88) | 0% | (0 / 67) | 20.77% | (65 / 313) | |
| CodeGenerator.js | 6.62% | (10 / 151) | 0% | (0 / 75) | 0% | (0 / 23) | 6.62% | (10 / 151) | |
| CodeWriter.js | 6.29% | (9 / 143) | 0% | (0 / 89) | 0% | (0 / 13) | 6.29% | (9 / 143) | |
| CompileContext.js | 7.33% | (25 / 341) | 0% | (0 / 202) | 0% | (0 / 53) | 7.35% | (25 / 340) | |
| CompileError.js | 4% | (1 / 25) | 0% | (0 / 18) | 0% | (0 / 2) | 4% | (1 / 25) | |
| Compiler.js | 21.79% | (17 / 78) | 0% | (0 / 16) | 9.09% | (1 / 11) | 22.08% | (17 / 77) | |
| HtmlJsParser.js | 9.38% | (3 / 32) | 14.29% | (2 / 14) | 7.14% | (1 / 14) | 9.38% | (3 / 32) | |
| InlineCompiler.js | 9.09% | (4 / 44) | 0% | (0 / 22) | 0% | (0 / 5) | 9.09% | (4 / 44) | |
| Parser.js | 7.61% | (15 / 197) | 1.98% | (2 / 101) | 4.76% | (1 / 21) | 7.61% | (15 / 197) | |
| Walker.js | 4.94% | (4 / 81) | 0% | (0 / 55) | 0% | (0 / 10) | 4.94% | (4 / 81) | |
| config.js | 85.71% | (6 / 7) | 64.29% | (9 / 14) | 100% | (0 / 0) | 85.71% | (6 / 7) | |
| index.js | 43.92% | (65 / 148) | 0% | (0 / 32) | 10.53% | (2 / 19) | 43.92% | (65 / 148) | |
| modules.js | 69.23% | (9 / 13) | 0% | (0 / 3) | 20% | (1 / 5) | 69.23% | (9 / 13) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var isArray = Array.isArray;
var ok = require('assert').ok;
var Node = require('./ast/Node');
var Program = require('./ast/Program');
var TemplateRoot = require('./ast/TemplateRoot');
var FunctionDeclaration = require('./ast/FunctionDeclaration');
var FunctionCall = require('./ast/FunctionCall');
var Literal = require('./ast/Literal');
var Identifier = require('./ast/Identifier');
var Comment = require('./ast/Comment');
var If = require('./ast/If');
var ElseIf = require('./ast/ElseIf');
var Else = require('./ast/Else');
var Assignment = require('./ast/Assignment');
var BinaryExpression = require('./ast/BinaryExpression');
var LogicalExpression = require('./ast/LogicalExpression');
var Vars = require('./ast/Vars');
var Return = require('./ast/Return');
var HtmlElement = require('./ast/HtmlElement');
var Html = require('./ast/Html');
var Text = require('./ast/Text');
var ForEach = require('./ast/ForEach');
var ForEachProp = require('./ast/ForEachProp');
var ForRange = require('./ast/ForRange');
var HtmlComment = require('./ast/HtmlComment');
var SelfInvokingFunction = require('./ast/SelfInvokingFunction');
var ForStatement = require('./ast/ForStatement');
var BinaryExpression = require('./ast/BinaryExpression');
var UpdateExpression = require('./ast/UpdateExpression');
var UnaryExpression = require('./ast/UnaryExpression');
var MemberExpression = require('./ast/MemberExpression');
var Code = require('./ast/Code');
var InvokeMacro = require('./ast/InvokeMacro');
var Macro = require('./ast/Macro');
var ConditionalExpression = require('./ast/ConditionalExpression');
var NewExpression = require('./ast/NewExpression');
var ObjectExpression = require('./ast/ObjectExpression');
var ArrayExpression = require('./ast/ArrayExpression');
var Property = require('./ast/Property');
var VariableDeclarator = require('./ast/VariableDeclarator');
var ThisExpression = require('./ast/ThisExpression');
var Expression = require('./ast/Expression');
var Scriptlet = require('./ast/Scriptlet');
var ContainerNode = require('./ast/ContainerNode');
var WhileStatement = require('./ast/WhileStatement');
var DocumentType = require('./ast/DocumentType');
var Declaration = require('./ast/Declaration');
var SequenceExpression = require('./ast/SequenceExpression');
var CustomTag = require('./ast/CustomTag');
var parseExpression = require('./util/parseExpression');
var parseStatement = require('./util/parseStatement');
var parseJavaScriptArgs = require('./util/parseJavaScriptArgs');
var replacePlaceholderEscapeFuncs = require('./util/replacePlaceholderEscapeFuncs');
var isValidJavaScriptIdentifier = require('./util/isValidJavaScriptIdentifier');
var DEFAULT_BUILDER;
function makeNode(arg) {
if (typeof arg === 'string') {
return parseExpression(arg, DEFAULT_BUILDER);
} else if (arg instanceof Node) {
return arg;
} else if (arg == null) {
return undefined;
} else if (Array.isArray(arg)) {
return arg.map((arg) => {
return makeNode(arg);
});
} else {
throw new Error('Argument should be a string or Node or null. Actual: ' + arg);
}
}
var literalNull = new Literal({value: null});
var literalUndefined = new Literal({value: undefined});
var literalTrue = new Literal({value: true});
var literalFalse = new Literal({value: false});
var identifierOut = new Identifier({name: 'out'});
var identifierRequire = new Identifier({name: 'require'});
class Builder {
arrayExpression(elements) {
if (elements) {
if (!isArray(elements)) {
elements = [elements];
}
for (var i=0; i<elements.length; i++) {
elements[i] = makeNode(elements[i]);
}
} else {
elements = [];
}
return new ArrayExpression({elements});
}
assignment(left, right, operator) {
if (operator == null) {
operator = '=';
}
left = makeNode(left);
right = makeNode(right);
return new Assignment({left, right, operator});
}
binaryExpression(left, operator, right) {
left = makeNode(left);
right = makeNode(right);
return new BinaryExpression({left, operator, right});
}
sequenceExpression(expressions) {
expressions = makeNode(expressions);
return new SequenceExpression({expressions});
}
code(value) {
return new Code({value});
}
computedMemberExpression(object, property) {
object = makeNode(object);
property = makeNode(property);
let computed = true;
return new MemberExpression({object, property, computed});
}
concat(args) {
var prev;
let operator = '+';
for (var i=1; i<arguments.length; i++) {
var left;
var right = makeNode(arguments[i]);
if (i === 1) {
left = makeNode(arguments[i-1]);
} else {
left = prev;
}
prev = new BinaryExpression({left, operator, right});
}
return prev;
}
conditionalExpression(test, consequent, alternate) {
return new ConditionalExpression({test, consequent, alternate});
}
containerNode(type, generateCode) {
if (typeof type === 'function') {
generateCode = arguments[0];
type = 'ContainerNode';
}
var node = new ContainerNode(type);
if (generateCode) {
node.setCodeGenerator(generateCode);
}
return node;
}
customTag(el, tagDef) {
return new CustomTag(el, tagDef);
}
declaration(declaration) {
return new Declaration({declaration});
}
documentType(documentType) {
return new DocumentType({documentType});
}
elseStatement(body) {
return new Else({body});
}
elseIfStatement(test, body, elseStatement) {
test = makeNode(test);
return new ElseIf({test, body, else: elseStatement});
}
expression(value) {
return new Expression({value});
}
forEach(varName, inExpression, body) {
if (arguments.length === 1) {
var def = arguments[0];
return new ForEach(def);
} else {
varName = makeNode(varName);
inExpression = makeNode(inExpression);
return new ForEach({varName, in: inExpression, body});
}
}
forEachProp(nameVarName, valueVarName, inExpression, body) {
if (arguments.length === 1) {
var def = arguments[0];
return new ForEachProp(def);
} else {
nameVarName = makeNode(nameVarName);
valueVarName = makeNode(valueVarName);
inExpression = makeNode(inExpression);
return new ForEachProp({nameVarName, valueVarName, in: inExpression, body});
}
}
forRange(varName, from, to, step, body) {
if (arguments.length === 1) {
var def = arguments[0];
return new ForRange(def);
} else {
varName = makeNode(varName);
from = makeNode(from);
to = makeNode(to);
step = makeNode(step);
body = makeNode(body);
return new ForRange({varName, from, to, step, body});
}
}
forStatement(init, test, update, body) {
if (arguments.length === 1) {
var def = arguments[0];
return new ForStatement(def);
} else {
init = makeNode(init);
test = makeNode(test);
update = makeNode(update);
return new ForStatement({init, test, update, body});
}
}
functionCall(callee, args) {
callee = makeNode(callee);
if (args) {
if (!isArray(args)) {
throw new Error('"args" should be an array');
}
for (var i=0; i<args.length; i++) {
args[i] = makeNode(args[i]);
}
} else {
args = [];
}
return new FunctionCall({callee, args});
}
functionDeclaration(name, params, body) {
return new FunctionDeclaration({name, params, body});
}
html(argument) {
argument = makeNode(argument);
return new Html({argument});
}
htmlComment(comment) {
return new HtmlComment({comment});
}
comment(comment) {
return new Comment({comment});
}
htmlElement(tagName, attributes, body, argument, openTagOnly, selfClosed) {
if (typeof tagName === 'object' && !(tagName instanceof Node)) {
let def = arguments[0];
return new HtmlElement(def);
} else {
return new HtmlElement({tagName, attributes, body, argument, openTagOnly, selfClosed});
}
}
htmlLiteral(htmlCode) {
var argument = new Literal({value: htmlCode});
return new Html({argument});
}
identifier(name) {
ok(typeof name === 'string', '"name" should be a string');
if (!isValidJavaScriptIdentifier(name)) {
var error = new Error('Invalid JavaScript identifier: ' + name);
error.code = 'INVALID_IDENTIFIER';
throw error;
}
return new Identifier({name});
}
identifierOut(name) {
return identifierOut;
}
ifStatement(test, body, elseStatement) {
test = makeNode(test);
return new If({test, body, else: elseStatement});
}
invokeMacro(name, args, body) {
return new InvokeMacro({name, args, body});
}
invokeMacroFromEl(el) {
return new InvokeMacro({el});
}
literal(value) {
return new Literal({value});
}
literalFalse() {
return literalFalse;
}
literalNull() {
return literalNull;
}
literalTrue() {
return literalTrue;
}
literalUndefined() {
return literalUndefined;
}
logicalExpression(left, operator, right) {
left = makeNode(left);
right = makeNode(right);
return new LogicalExpression({left, operator, right});
}
macro(name, params, body) {
return new Macro({name, params, body});
}
memberExpression(object, property, computed) {
object = makeNode(object);
property = makeNode(property);
return new MemberExpression({object, property, computed});
}
moduleExports(value) {
let object = new Identifier({name: 'module'});
let property = new Identifier({name: 'exports'});
var moduleExports = new MemberExpression({object, property });
if (value) {
return new Assignment({left: moduleExports, right: value, operator: '='});
} else {
return moduleExports;
}
}
negate(argument) {
argument = makeNode(argument);
var operator = '!';
var prefix = true;
return new UnaryExpression({argument, operator, prefix});
}
newExpression(callee, args) {
callee = makeNode(callee);
if (args) {
if (!isArray(args)) {
args = [args];
}
for (var i=0; i<args.length; i++) {
args[i] = makeNode(args[i]);
}
} else {
args = [];
}
return new NewExpression({callee, args});
}
node(type, generateCode) {
if (typeof type === 'function') {
generateCode = arguments[0];
type = 'Node';
}
var node = new Node(type);
if (generateCode) {
node.setCodeGenerator(generateCode);
}
return node;
}
objectExpression(properties) {
if (properties) {
if (!isArray(properties)) {
properties = [properties];
}
for (var i=0; i<properties.length; i++) {
let prop = properties[i];
prop.value = makeNode(prop.value);
}
} else {
properties = [];
}
return new ObjectExpression({properties});
}
parseExpression(str, options) {
ok(typeof str === 'string', '"str" should be a string expression');
var parsed = parseExpression(str, DEFAULT_BUILDER);
return parsed;
}
parseJavaScriptArgs(args) {
ok(typeof args === 'string', '"args" should be a string');
return parseJavaScriptArgs(args, DEFAULT_BUILDER);
}
parseStatement(str, options) {
ok(typeof str === 'string', '"str" should be a string expression');
var parsed = parseStatement(str, DEFAULT_BUILDER);
return parsed;
}
replacePlaceholderEscapeFuncs(node, context) {
return replacePlaceholderEscapeFuncs(node, context);
}
program(body) {
return new Program({body});
}
property(key, value) {
key = makeNode(key);
value = makeNode(value);
return new Property({key, value});
}
renderBodyFunction(body, params) {
let name = 'renderBody';
if (!params) {
params = [new Identifier({name: 'out'})];
}
return new FunctionDeclaration({name, params, body});
}
require(path) {
path = makeNode(path);
let callee = identifierRequire;
let args = [ path ];
return new FunctionCall({callee, args});
}
requireResolve(path) {
path = makeNode(path);
let callee = new MemberExpression({
object: new Identifier({name: 'require'}),
property: new Identifier({name: 'resolve'})
});
let args = [ path ];
return new FunctionCall({callee, args});
}
returnStatement(argument) {
argument = makeNode(argument);
return new Return({argument});
}
scriptlet(scriptlet) {
return new Scriptlet({
code: scriptlet.value,
tag: scriptlet.tag,
block: scriptlet.block
});
}
selfInvokingFunction(params, args, body) {
if (arguments.length === 1) {
body = arguments[0];
params = null;
args = null;
}
return new SelfInvokingFunction({params, args, body});
}
strictEquality(left, right) {
left = makeNode(left);
right = makeNode(right);
var operator = '===';
return new BinaryExpression({left, right, operator});
}
templateRoot(body) {
return new TemplateRoot({body});
}
text(argument, escape, preserveWhitespace) {
if (typeof argument === 'object' && !(argument instanceof Node)) {
var def = arguments[0];
return new Text(def);
}
argument = makeNode(argument);
return new Text({argument, escape, preserveWhitespace});
}
thisExpression() {
return new ThisExpression();
}
unaryExpression(argument, operator, prefix) {
argument = makeNode(argument);
return new UnaryExpression({argument, operator, prefix});
}
updateExpression(argument, operator, prefix) {
argument = makeNode(argument);
return new UpdateExpression({argument, operator, prefix});
}
variableDeclarator(id, init) {
if (typeof id === 'string') {
id = new Identifier({name: id});
}
if (init) {
init = makeNode(init);
}
return new VariableDeclarator({id, init});
}
var(id, init, kind) {
if (!kind) {
kind = 'var';
}
id = makeNode(id);
init = makeNode(init);
var declarations = [
new VariableDeclarator({id, init})
];
return new Vars({declarations, kind});
}
vars(declarations, kind) {
if (declarations) {
if (Array.isArray(declarations)) {
for (let i=0; i<declarations.length; i++) {
var declaration = declarations[i];
if (!declaration) {
throw new Error('Invalid variable declaration');
}
if (typeof declaration === 'string') {
declarations[i] = new VariableDeclarator({
id: new Identifier({name: declaration})
});
} else if (declaration instanceof Identifier) {
declarations[i] = new VariableDeclarator({
id: declaration
});
} else if (typeof declaration === 'object') {
if (!(declaration instanceof VariableDeclarator)) {
let id = declaration.id;
let init = declaration.init;
if (typeof id === 'string') {
id = new Identifier({name: id});
}
if (!id) {
throw new Error('Invalid variable declaration');
}
if (init) {
init = makeNode(init);
}
declarations[i] = new VariableDeclarator({id, init});
}
}
}
} else if (typeof declarations === 'object') {
// Convert the object into an array of variables
declarations = Object.keys(declarations).map((key) => {
let id = new Identifier({name: key});
let init = makeNode(declarations[key]);
return new VariableDeclarator({ id, init });
});
}
}
return new Vars({declarations, kind});
}
whileStatement(test, body) {
return new WhileStatement({test, body});
}
}
DEFAULT_BUILDER = new Builder();
Builder.DEFAULT_BUILDER = DEFAULT_BUILDER;
module.exports = Builder;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 | 1 1 1 1 1 1 1 1 1 1 | 'use strict';
const isArray = Array.isArray;
const Node = require('./ast/Node');
const Literal = require('./ast/Literal');
const Identifier = require('./ast/Identifier');
const HtmlElement = require('./ast/HtmlElement');
const Html = require('./ast/Html');
const ok = require('assert').ok;
const Container = require('./ast/Container');
const createError = require('raptor-util/createError');
class GeneratorEvent {
constructor(node, codegen) {
this.node = node;
this.codegen = codegen;
this.isBefore = true;
this.builder = codegen.builder;
this.context = codegen.context;
this.insertedNodes = null;
}
insertCode(newCode) {
if (!this.insertedNodes) {
this.insertedNodes = [];
}
this.insertedNodes = this.insertedNodes.concat(newCode);
}
}
class FinalNodes {
constructor() {
this.nodes = [];
this.nodes._finalNode = true; // Mark the array as a collection of final nodes
this.lastNode = null;
}
push(node) {
if (!node) {
return;
}
if (node instanceof Html) {
if (this.lastNode instanceof Html) {
this.lastNode.append(node);
return;
}
}
if (node.setFinalNode) {
node.setFinalNode(true);
}
this.lastNode = node;
this.nodes.push(node);
}
}
class CodeGenerator {
constructor(context, options) {
options = options || {};
this.root = null;
this._code = '';
this.currentIndent = '';
this.inFunction = false;
this._doneListeners = [];
this.builder = context.builder;
this.context = context;
ok(this.builder, '"this.builder" is required');
this._codegenCodeMethodName = 'generate' +
context.outputType.toUpperCase() +
'Code';
}
addVar(name, value) {
return this.context.addVar(name, value);
}
addStaticVar(name, value) {
return this.context.addStaticVar(name, value);
}
addStaticCode(code) {
this.context.addStaticCode(code);
}
addDependency(path, type, options) {
this.context.addDependency(path, type, options);
}
pushMeta(key, value, unique) {
this.context.pushMeta(key, value, unique);
}
setMeta(key, value) {
this.context.setMeta(key, value);
}
getEscapeXmlAttrVar() {
return this.context.getEscapeXmlAttrVar();
}
importModule(varName, path) {
return this.context.importModule(varName, path);
}
_invokeCodeGenerator(func, node, isMethod) {
try {
if (isMethod) {
return func.call(node, this);
} else {
return func.call(node, node, this);
}
} catch(err) {
var errorMessage = 'Generating code for ';
if (node instanceof HtmlElement) {
errorMessage += '<'+node.tagName+'> tag';
} else {
errorMessage += node.type + ' node';
}
if (node.pos) {
errorMessage += ' ('+this.context.getPosInfo(node.pos)+')';
}
errorMessage += ' failed. Error: ' + err;
throw createError(errorMessage, err /* cause */);
}
}
_generateCode(node, finalNodes) {
if (isArray(node)) {
node.forEach((child) => {
this._generateCode(child, finalNodes);
});
return;
} else if (node instanceof Container) {
node.forEach((child) => {
if (child.container === node) {
this._generateCode(child, finalNodes);
}
});
return;
}
if (node == null) {
return;
}
if (typeof node === 'string' || node._finalNode || !(node instanceof Node)) {
finalNodes.push(node);
return;
}
if (node._normalizeChildTextNodes) {
node._normalizeChildTextNodes(this.context);
}
let oldCurrentNode = this._currentNode;
this._currentNode = node;
var beforeAfterEvent = new GeneratorEvent(node, this);
var isWhitespacePreserved = node.isPreserveWhitespace();
if (isWhitespacePreserved) {
this.context.beginPreserveWhitespace();
}
beforeAfterEvent.isBefore = true;
beforeAfterEvent.node.emit('beforeGenerateCode', beforeAfterEvent);
this.context.emit('beforeGenerateCode:' + beforeAfterEvent.node.type, beforeAfterEvent);
this.context.emit('beforeGenerateCode', beforeAfterEvent);
if (beforeAfterEvent.insertedNodes) {
this._generateCode(beforeAfterEvent.insertedNodes, finalNodes);
beforeAfterEvent.insertedNodes = null;
}
let codeGeneratorFunc;
let generatedCode;
if (node.getCodeGenerator) {
codeGeneratorFunc = node.getCodeGenerator(this.outputType);
if (codeGeneratorFunc) {
node.setCodeGenerator(null);
generatedCode = this._invokeCodeGenerator(codeGeneratorFunc, node, false);
if (generatedCode === null) {
node = null;
} else if (generatedCode !== undefined && generatedCode !== node) {
node = null;
this._generateCode(generatedCode, finalNodes);
}
}
}
if (node != null) {
codeGeneratorFunc = node.generateCode;
if (!codeGeneratorFunc) {
codeGeneratorFunc = node[this._codegenCodeMethodName];
}
if (codeGeneratorFunc) {
generatedCode = this._invokeCodeGenerator(codeGeneratorFunc, node, true);
if (generatedCode === undefined || generatedCode === node) {
finalNodes.push(node);
} else if (generatedCode === null) {
// If nothing was returned then don't generate any code
} else {
this._generateCode(generatedCode, finalNodes);
}
} else {
finalNodes.push(node);
}
}
beforeAfterEvent.isBefore = false;
beforeAfterEvent.node.emit('afterGenerateCode', beforeAfterEvent);
this.context.emit('afterGenerateCode:' + beforeAfterEvent.node.type, beforeAfterEvent);
this.context.emit('afterGenerateCode', beforeAfterEvent);
if (beforeAfterEvent.insertedNodes) {
this._generateCode(beforeAfterEvent.insertedNodes, finalNodes);
beforeAfterEvent.insertedNodes = null;
}
if (isWhitespacePreserved) {
this.context.endPreserveWhitespace();
}
this._currentNode = oldCurrentNode;
}
generateCode(node) {
if (!node) {
return null;
}
if (node._finalNode) {
return node;
}
let finalNodes = new FinalNodes();
var isList = typeof node.forEach === 'function';
this._generateCode(node, finalNodes);
finalNodes = finalNodes.nodes;
if (!isList) {
if (finalNodes.length === 0) {
return null;
} else if (finalNodes.length === 1) {
return finalNodes[0];
}
}
return finalNodes;
}
isLiteralNode(node) {
return node instanceof Literal;
}
isIdentifierNode(node) {
return node instanceof Identifier;
}
isPreserveWhitespaceEnabled() {
return false;
}
addError(message, code) {
ok('"message" is required');
let node = this._currentNode;
if (typeof message === 'object') {
let errorInfo = message;
errorInfo.node = node;
this.context.addError(errorInfo);
} else {
this.context.addError({node, message, code});
}
}
onDone(listenerFunc) {
this._doneListeners.push(listenerFunc);
}
getRequirePath(targetFilename) {
return this.context.getRequirePath(targetFilename);
}
resolvePath(pathExpression) {
return this.context.resolvePath(pathExpression);
}
}
module.exports = CodeGenerator;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | 1 1 1 1 1 1 1 1 1 | 'use strict';
const isArray = Array.isArray;
const Node = require('./ast/Node');
const Literal = require('./ast/Literal');
const Identifier = require('./ast/Identifier');
const ok = require('assert').ok;
const Container = require('./ast/Container');
const Comment = require('./ast/Comment');
const isValidJavaScriptVarName = require('./util/isValidJavaScriptVarName');
class CodeWriter {
constructor(options, builder) {
ok(builder, '"builder" is required');
options = options || {};
this.builder = builder;
this.root = null;
this._indentStr = options.indent != null ? options.indent : ' ';
this._indentSize = this._indentStr.length;
this._code = '';
this.currentIndent = '';
}
getCode() {
return this._code;
}
writeBlock(body) {
if (!body) {
this.write('{}');
return;
}
if (typeof body === 'function') {
body = body();
}
if (!body ||
(Array.isArray(body) && body.length === 0) ||
(body instanceof Container && body.length === 0)) {
this.write('{}');
return;
}
this.write('{\n')
.incIndent();
this.writeStatements(body);
this.decIndent()
.writeLineIndent()
.write('}');
}
writeStatements(nodes) {
if (!nodes) {
return;
}
ok(nodes, '"nodes" expected');
let firstStatement = true;
var writeNode = (node) => {
if (Array.isArray(node) || (node instanceof Container)) {
node.forEach(writeNode);
return;
} else {
if (firstStatement) {
firstStatement = false;
} else {
this._write('\n');
}
this.writeLineIndent();
if (typeof node === 'string') {
this._write(node);
} else {
node.statement = true;
this.write(node);
}
if (this._code.endsWith('\n')) {
// Do nothing
} else if (this._code.endsWith(';')) {
this._code += '\n';
} else if (this._code.endsWith('\n' + this.currentIndent) || node instanceof Comment) {
// Do nothing
} else {
this._code += ';\n';
}
}
};
if (nodes instanceof Node) {
writeNode(nodes);
} else {
nodes.forEach(writeNode);
}
}
write(code) {
if (code == null || code === '') {
return;
}
if (code instanceof Node) {
let node = code;
if (!node.writeCode) {
throw new Error('Node does not have a `writeCode` method: ' + JSON.stringify(node, null, 4));
}
node.writeCode(this);
} else if (isArray(code) || code instanceof Container) {
code.forEach(this.write, this);
return;
} else if (typeof code === 'string') {
this._code += code;
} else if (typeof code === 'boolean' || typeof code === 'number') {
this._code += code.toString();
} else {
throw new Error('Illegal argument: ' + JSON.stringify(code));
}
return this;
}
_write(code) {
this._code += code;
return this;
}
incIndent(count) {
if (count != null) {
for (let i=0; i<count; i++) {
this.currentIndent += ' ';
}
} else {
this.currentIndent += this._indentStr;
}
return this;
}
decIndent(count) {
if (count == null) {
count = this._indentSize;
}
this.currentIndent = this.currentIndent.substring(
0,
this.currentIndent.length - count);
return this;
}
writeLineIndent() {
this._code += this.currentIndent;
return this;
}
writeIndent() {
this._code += this._indentStr;
return this;
}
isLiteralNode(node) {
return node instanceof Literal;
}
isIdentifierNode(node) {
return node instanceof Identifier;
}
writeLiteral(value) {
if (value === null) {
this.write('null');
} else if (value === undefined) {
this.write('undefined');
} else if (typeof value === 'string') {
this.write(JSON.stringify(value));
} else if (value === true) {
this.write('true');
} else if (value === false) {
this.write('false');
} else if (isArray(value)) {
if (value.length === 0) {
this.write('[]');
return;
}
this.write('[\n');
this.incIndent();
for (let i=0; i<value.length; i++) {
let v = value[i];
this.writeLineIndent();
if (v instanceof Node) {
this.write(v);
} else {
this.writeLiteral(v);
}
if (i < value.length - 1) {
this.write(',\n');
} else {
this.write('\n');
}
}
this.decIndent();
this.writeLineIndent();
this.write(']');
} else if (typeof value === 'number') {
this.write(value.toString());
} else if (value instanceof RegExp) {
this.write(value.toString());
} else if (typeof value === 'object') {
let keys = Object.keys(value);
if (keys.length === 0) {
this.write('{}');
return;
}
this.incIndent();
this.write('{\n');
this.incIndent();
for (let i=0; i<keys.length; i++) {
let k = keys[i];
let v = value[k];
this.writeLineIndent();
if (isValidJavaScriptVarName(k)) {
this.write(k + ': ');
} else {
this.write(JSON.stringify(k) + ': ');
}
if (v instanceof Node) {
this.write(v);
} else {
this.writeLiteral(v);
}
if (i < keys.length - 1) {
this.write(',\n');
} else {
this.write('\n');
}
}
this.decIndent();
this.writeLineIndent();
this.write('}');
this.decIndent();
}
}
}
module.exports = CodeWriter;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var ok = require('assert').ok;
var path = require('path');
var complain = require('complain');
var taglibLookup = require('./taglib-lookup');
var charProps = require('char-props');
var UniqueVars = require('./util/UniqueVars');
var PosInfo = require('./util/PosInfo');
var CompileError = require('./CompileError');
var path = require('path');
var Node = require('./ast/Node');
var macros = require('./util/macros');
var extend = require('raptor-util/extend');
var Walker = require('./Walker');
var EventEmitter = require('events').EventEmitter;
var utilFingerprint = require('./util/finger-print');
var htmlElements = require('./util/html-elements');
var markoModules = require('./modules');
const markoPkgVersion = require('../package.json').version;
const FLAG_PRESERVE_WHITESPACE = 'PRESERVE_WHITESPACE';
function getTaglibPath(taglibPath) {
if (typeof window === 'undefined') {
return path.relative(process.cwd(), taglibPath);
} else {
return taglibPath;
}
}
function removeExt(filename) {
var ext = path.extname(filename);
if (ext) {
return filename.slice(0, 0 - ext.length);
} else {
return filename;
}
}
function requireResolve(builder, path) {
var requireResolveNode = builder.memberExpression(
builder.identifier('require'),
builder.identifier('resolve'));
return builder.functionCall(requireResolveNode, [ path ]);
}
const helpers = {
'attr': 'a',
'attrs': 'as',
'classAttr': 'ca',
'classList': 'cl',
'const': 'const',
'createElement': 'e',
'createInlineTemplate': {
vdom: { module: 'marko/runtime/vdom/helper-createInlineTemplate'},
html: { module: 'marko/runtime/html/helper-createInlineTemplate'}
},
'escapeXml': 'x',
'escapeXmlAttr': 'xa',
'escapeScript': 'xs',
'escapeStyle': 'xc',
'forEach': 'f',
'forEachProp': { module: 'marko/runtime/helper-forEachProperty' },
'forEachPropStatusVar': { module: 'marko/runtime/helper-forEachPropStatusVar' },
'forEachWithStatusVar': { module: 'marko/runtime/helper-forEachWithStatusVar' },
'forRange': { module: 'marko/runtime/helper-forRange' },
'include': 'i',
'loadNestedTag': { module: 'marko/runtime/helper-loadNestedTag' },
'loadTag': 't',
'loadTemplate': { module: 'marko/runtime/helper-loadTemplate' },
'mergeNestedTagsHelper': { module: 'marko/runtime/helper-mergeNestedTags' },
'merge': { module: 'marko/runtime/helper-merge' },
'renderComponent': { module: 'marko/components/taglib/helpers/renderComponent' },
'str': 's',
'styleAttr': {
vdom: { module: 'marko/runtime/vdom/helper-styleAttr'},
html: 'sa'
},
'createText': 't'
};
class CompileContext extends EventEmitter {
constructor(src, filename, builder, options) {
super();
ok(typeof src === 'string', '"src" string is required');
ok(filename, '"filename" is required');
this.src = src;
this.filename = filename;
this.builder = builder;
this.dirname = path.dirname(filename);
this.taglibLookup = taglibLookup.buildLookup(this.dirname);
this.data = {};
this._dataStacks = {};
this.meta = {};
this.options = options || {};
const writeVersionComment = this.options.writeVersionComment;
this.outputType = this.options.output || 'html';
this.compilerType = this.options.compilerType || 'marko';
this.compilerVersion = this.options.compilerVersion || markoPkgVersion;
this.writeVersionComment = writeVersionComment !== 'undefined' ? writeVersionComment : true;
this._vars = {};
this._uniqueVars = new UniqueVars();
this._staticVars = {};
this._staticCode = null;
this._uniqueStaticVars = new UniqueVars();
this._srcCharProps = null;
this._flags = {};
this._errors = [];
this._macros = null;
this._preserveWhitespace = null;
this._preserveComments = null;
this.inline = this.options.inline === true;
this.useMeta = this.options.meta !== false;
this._moduleRuntimeTarget = this.outputType === 'vdom' ? 'marko/vdom' : 'marko/html';
this.unrecognizedTags = [];
this._parsingFinished = false;
this._helpersIdentifier = null;
if (this.options.preserveWhitespace) {
this.setPreserveWhitespace(true);
}
this._helpers = {};
this._imports = {};
this._fingerprint = undefined;
this._optimizers = undefined;
}
setInline(isInline) {
this.inline = isInline === true;
}
getPosInfo(pos) {
var srcCharProps = this._srcCharProps || (this._srcCharProps = charProps(this.src));
let line = srcCharProps.lineAt(pos)+1;
let column = srcCharProps.columnAt(pos);
return new PosInfo(this.filename, line, column);
}
getNodePos(node) {
if (node.pos) {
return this.getPosInfo(node.pos);
} else {
return new PosInfo(this.filename);
}
}
setFlag(name) {
this.pushFlag(name);
}
clearFlag(name) {
delete this._flags[name];
}
isFlagSet(name) {
return this._flags.hasOwnProperty(name);
}
pushFlag(name) {
if (this._flags.hasOwnProperty(name)) {
this._flags[name]++;
} else {
this._flags[name] = 1;
}
}
popFlag(name) {
if (!this._flags.hasOwnProperty(name)) {
throw new Error('popFlag() called for "' + name + '" when flag was not set');
}
if (--this._flags[name] === 0) {
delete this._flags[name];
}
}
pushData(key, data) {
var dataStack = this._dataStacks[key];
if (!dataStack) {
dataStack = this._dataStacks[key] = [];
}
dataStack.push(data);
return {
pop: () => {
this.popData(key);
}
};
}
popData(key) {
var dataStack = this._dataStacks[key];
if (!dataStack || dataStack.length === 0) {
throw new Error('No data pushed for "' + key + '"');
}
dataStack.pop();
if (dataStack.length === 0) {
delete this.data[key];
}
}
getData(name) {
var dataStack = this._dataStacks[name];
if (dataStack) {
return dataStack[dataStack.length - 1];
}
return this.data[name];
}
deprecate(message, node) {
var currentNode = node || this._currentNode;
var location = currentNode && currentNode.pos;
if (location != null) {
location = this.getPosInfo(location).toString();
}
complain(message, { location });
}
addError(errorInfo) {
if (errorInfo instanceof Node) {
let node = arguments[0];
let message = arguments[1];
let code = arguments[2];
let pos = arguments[3];
errorInfo = {
node,
message,
code,
pos
};
} else if (typeof errorInfo === 'string') {
let message = arguments[0];
let code = arguments[1];
let pos = arguments[2];
errorInfo = {
message,
code,
pos
};
}
if(errorInfo && !errorInfo.node) {
errorInfo.node = this._currentNode;
}
this._errors.push(new CompileError(errorInfo, this));
}
hasErrors() {
return this._errors.length !== 0;
}
getErrors() {
return this._errors;
}
getRequirePath(targetFilename) {
return markoModules.deresolve(targetFilename, this.dirname);
}
importModule(varName, path) {
if (typeof path !== 'string') {
throw new Error('"path" should be a string');
}
var varId = this._imports[path];
if (!varId) {
var builder = this.builder;
var requireFuncCall = this.builder.require(builder.literal(path));
this._imports[path] = varId = this.addStaticVar(varName, requireFuncCall);
}
return varId;
}
addVar(name, init) {
var actualVarName = this._uniqueVars.addVar(name, init);
this._vars[actualVarName] = init;
return this.builder.identifier(actualVarName);
}
getVars() {
return this._vars;
}
addStaticVar(name, init) {
var actualVarName = this._uniqueStaticVars.addVar(name, init);
this._staticVars[actualVarName] = init;
return this.builder.identifier(actualVarName);
}
getStaticVars() {
return this._staticVars;
}
addStaticCode(code) {
if (!code) {
return;
}
if (typeof code === 'string') {
// Wrap the String code in a Code AST node so that
// the code will be indented properly
code = this.builder.code(code);
}
if (this._staticCode == null) {
this._staticCode = [code];
} else {
this._staticCode.push(code);
}
}
getStaticCode() {
return this._staticCode;
}
getTagDef(tagName) {
var taglibLookup = this.taglibLookup;
if (typeof tagName === 'string') {
return taglibLookup.getTag(tagName);
} else {
let elNode = tagName;
if (elNode.tagDef) {
return elNode.tagDef;
}
return taglibLookup.getTag(elNode.tagName);
}
}
addErrorUnrecognizedTag(tagName, elNode) {
this.addError({
node: elNode,
message: 'Unrecognized tag: ' + tagName + ' - More details: https://github.com/marko-js/marko/wiki/Error:-Unrecognized-Tag'
});
}
createNodeForEl(tagName, attributes, argument, openTagOnly, selfClosed) {
var elDef;
var builder = this.builder;
if (typeof tagName === 'object') {
elDef = tagName;
tagName = elDef.tagName;
attributes = elDef.attributes;
} else {
elDef = { tagName, argument, attributes, openTagOnly, selfClosed };
}
if (elDef.tagName === '') {
elDef.tagName = tagName = 'assign';
}
if (!attributes) {
attributes = elDef.attributes = [];
} else if (typeof attributes === 'object') {
if (!Array.isArray(attributes)) {
attributes = elDef.attributes = Object.keys(attributes).map((attrName) => {
var attrDef = {
name: attrName
};
var val = attributes[attrName];
if (val == null) {
} if (val instanceof Node) {
attrDef.value = val;
} else {
extend(attrDef, val);
}
return attrDef;
});
}
} else {
throw new Error('Invalid attributes');
}
var node;
var elNode = builder.htmlElement(elDef);
elNode.pos = elDef.pos;
this._currentNode = elNode;
var tagDef;
var taglibLookup = this.taglibLookup;
if (typeof tagName === 'string' && tagName.startsWith('@')) {
// NOTE: The tag definition can't be determined now since it will be
// determined by the parent custom tag.
node = builder.customTag(elNode);
node.body = node.makeContainer(node.body.items);
} else {
if (typeof tagName === 'string') {
tagDef = taglibLookup.getTag(tagName);
if (!tagDef &&
!this.isMacro(tagName) &&
tagName.indexOf(':') === -1 &&
!htmlElements.isRegisteredElement(tagName, this.dirname)) {
if (this._parsingFinished) {
this.addErrorUnrecognizedTag(tagName, elNode);
} else {
// We don't throw an error right away since the tag
// may be a macro that gets registered later
this.unrecognizedTags.push({
node: elNode,
tagName: tagName
});
}
}
}
if (tagDef) {
var nodeFactoryFunc = tagDef.getNodeFactory();
if (nodeFactoryFunc) {
var newNode = nodeFactoryFunc(elNode, this);
if (!(newNode instanceof Node)) {
throw new Error('Invalid node returned from node factory for tag "' + tagName + '".');
}
if (newNode != node) {
// Make sure the body container is associated with the correct node
if (newNode.body && newNode.body !== node) {
newNode.body = newNode.makeContainer(newNode.body.items);
}
node = newNode;
}
}
}
if (!node) {
node = elNode;
}
}
if (tagDef && tagDef.noOutput) {
node.noOutput = true;
}
node.pos = elDef.pos;
var foundAttrs = {};
// Validate the attributes
attributes.forEach((attr) => {
let attrName = attr.name;
if (!attrName) {
// Attribute will be name for placeholder attributes. For example: <div ${data.myAttrs}>
return;
}
let attrDef = taglibLookup.getAttribute(tagName, attrName);
if (!attrDef) {
if (tagDef) {
if (node.removeAttribute) {
node.removeAttribute(attrName);
}
// var isAttrForTaglib = compiler.taglibs.isTaglib(attrUri);
//Tag doesn't allow dynamic attributes
this.addError({
node: node,
message: 'The tag "' + tagName + '" in taglib "' + getTaglibPath(tagDef.taglibId) + '" does not support attribute "' + attrName + '"'
});
}
return;
}
if (attrDef.setFlag) {
node.setFlag(attrDef.setFlag);
}
attr.def = attrDef;
foundAttrs[attrName] = true;
});
if (tagDef) {
// Add default values for any attributes. If an attribute has a declared
// default value and the attribute was not found on the element
// then add the attribute with the specified default value
tagDef.forEachAttribute((attrDef) => {
var attrName = attrDef.name;
if (attrDef.hasOwnProperty('defaultValue') && !foundAttrs.hasOwnProperty(attrName)) {
attributes.push({
name: attrName,
value: builder.literal(attrDef.defaultValue)
});
} else if (attrDef.required === true) {
// TODO Only throw an error if there is no data argument provided (just HTML attributes)
if (!foundAttrs.hasOwnProperty(attrName)) {
this.addError({
node: node,
message: 'The "' + attrName + '" attribute is required for tag "' + tagName + '" in taglib "' + getTaglibPath(tagDef.taglibId) + '".'
});
}
}
});
node.tagDef = tagDef;
}
return node;
}
isMacro(name) {
if (!this._macros) {
return false;
}
return this._macros.isMacro(name);
}
getRegisteredMacro(name) {
if (!this._macros) {
return undefined;
}
return this._macros.getRegisteredMacro(name);
}
registerMacro(name, params) {
if (!this._macros) {
this._macros = macros.createMacrosContext();
}
return this._macros.registerMacro(name, params);
}
importTemplate(relativePath, varName) {
ok(typeof relativePath === 'string', '"path" should be a string');
var builder = this.builder;
varName = varName || removeExt(path.basename(relativePath)) + '_template';
var templateVar;
if (this.options.browser || this.options.requireTemplates) {
// When compiling a Marko template for the browser we just use `require('./template.marko')`
templateVar = this.addStaticVar(varName, builder.require(builder.literal(relativePath)));
} else {
// When compiling a Marko template for the server we just use `loadTemplate(require.resolve('./template.marko'))`
let loadTemplateArg = requireResolve(builder, builder.literal(relativePath));
let loadFunctionCall = builder.functionCall(this.helper('loadTemplate'), [ loadTemplateArg ]);
templateVar = this.addStaticVar(varName, loadFunctionCall);
}
this.pushMeta('tags', builder.literal(relativePath), true);
return templateVar;
}
addDependency(path, type, options) {
var dependency;
if(typeof path === 'object') {
dependency = path;
} else {
dependency = (type ? type+':' : '') + path;
}
this.pushMeta('deps', dependency, true);
}
pushMeta(key, value, unique) {
var property;
property = this.meta[key];
if(!property) {
this.meta[key] = [value];
} else if(!unique || !property.some(e => JSON.stringify(e) === JSON.stringify(value))) {
property.push(value);
}
}
setMeta(key, value) {
this.meta[key] = value;
}
setPreserveWhitespace(preserveWhitespace) {
this._preserveWhitespace = preserveWhitespace;
}
beginPreserveWhitespace() {
this.pushFlag(FLAG_PRESERVE_WHITESPACE);
}
endPreserveWhitespace() {
this.popFlag(FLAG_PRESERVE_WHITESPACE);
}
isPreserveWhitespace() {
if (this.isFlagSet(FLAG_PRESERVE_WHITESPACE) || this._preserveWhitespace === true) {
return true;
}
}
setPreserveComments(preserveComments) {
this._preserveComments = preserveComments;
}
isPreserveComments() {
return this._preserveComments === true;
}
createWalker(options) {
return new Walker(options);
}
/**
* Statically resolves a path if it is a literal string. Otherwise, it returns the input expression.
*/
resolvePath(pathExpression) {
ok(pathExpression, '"pathExpression" is required');
if (pathExpression.type === 'Literal') {
let path = pathExpression.value;
if (typeof path === 'string') {
return this.addStaticVar(path, this.builder.requireResolve(pathExpression));
}
}
return pathExpression;
}
resolveTemplate(pathExpression) {
ok(pathExpression, '"pathExpression" is required');
if (pathExpression.type === 'Literal') {
let path = pathExpression.value;
if (typeof path === 'string') {
return this.importTemplate(path);
}
}
return pathExpression;
}
getStaticNodes(additionalVars) {
let builder = this.builder;
let staticNodes = [];
let staticVars = this.getStaticVars();
let staticVarNodes = Object.keys(staticVars).map((varName) => {
var varInit = staticVars[varName];
return builder.variableDeclarator(varName, varInit);
});
if(additionalVars) {
staticVarNodes = additionalVars.concat(staticVarNodes);
}
if (staticVarNodes.length) {
staticNodes.push(this.builder.vars(staticVarNodes));
}
var staticCodeArray = this.getStaticCode();
if (staticCodeArray) {
staticNodes = staticNodes.concat(staticCodeArray);
}
return staticNodes;
}
get helpersIdentifier() {
if (!this._helpersIdentifier) {
var target = this.outputType === 'vdom' ? 'marko/runtime/vdom/helpers' : 'marko/runtime/html/helpers';
this._helpersIdentifier = this.importModule('marko_helpers', target);
}
return this._helpersIdentifier;
}
helper(name) {
var helperIdentifier = this._helpers[name];
if (!helperIdentifier) {
var helperInfo = helpers[name];
if (helperInfo && typeof helperInfo === 'object') {
if (!helperInfo.module) {
helperInfo = helperInfo[this.outputType];
}
}
if (!helperInfo) {
throw new Error('Invalid helper: ' + name);
}
if (typeof helperInfo === 'string') {
let methodName = helperInfo;
var methodIdentifier = this.builder.identifier(methodName);
helperIdentifier = this.addStaticVar(
'marko_' + name,
this.builder.memberExpression(this.helpersIdentifier, methodIdentifier));
} else if (helperInfo && helperInfo.module) {
helperIdentifier = this.addStaticVar(
'marko_' + name,
this.builder.require(this.builder.literal(helperInfo.module)));
} else {
throw new Error('Invalid helper: ' + name);
}
this._helpers[name] = helperIdentifier;
}
return helperIdentifier;
}
getFingerprint(len) {
var fingerprint = this._fingerprint;
if (!fingerprint) {
this._fingerprint = fingerprint = utilFingerprint(this.src);
}
if (len == null || len >= this._fingerprint) {
return fingerprint;
} else {
return fingerprint.substring(0, len);
}
}
addOptimizer(optimizer) {
if (this._optimizers) {
this._optimizers.push(optimizer);
} else {
this._optimizers = [optimizer];
}
}
optimize(rootNode) {
if (this._optimizers) {
this._optimizers.forEach((optimizer) => {
optimizer.optimize(rootNode, this);
});
}
}
getModuleRuntimeTarget() {
return this._moduleRuntimeTarget;
}
}
CompileContext.prototype.util = {
isValidJavaScriptIdentifier: require('./util/isValidJavaScriptIdentifier'),
isJavaScriptReservedWord: require('./util/isJavaScriptReservedWord')
};
module.exports = CompileContext;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | 1 | 'use strict';
class CompileError {
constructor(errorInfo, context) {
this.context = context;
this.node = errorInfo.node;
this.message = errorInfo.message;
this.code = errorInfo.code;
var pos = errorInfo.pos;
var endPos = errorInfo.endPos;
if (pos == null) {
pos = this.node && this.node.pos;
}
if (endPos == null) {
endPos = this.node && this.node.endPos;
}
if (pos != null) {
pos = context.getPosInfo(pos);
}
if (endPos != null) {
endPos = context.getPosInfo(endPos);
}
this.pos = pos;
this.endPos = endPos;
}
toString() {
var pos = this.pos;
if (pos) {
pos = '[' + pos + '] ';
} else {
pos = '';
}
var str = pos + this.message;
if (pos == null && this.node) {
str += ' (' + this.node.toString() + ')';
}
return str;
}
}
module.exports = CompileError;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var ok = require('assert').ok;
var path = require('path');
var CodeGenerator = require('./CodeGenerator');
var CodeWriter = require('./CodeWriter');
var createError = require('raptor-util/createError');
var resolveDep = require('../runtime/dependencies').resolveDep;
const FLAG_TRANSFORMER_APPLIED = 'transformerApply';
function transformNode(node, context) {
try {
context.taglibLookup.forEachNodeTransformer(node, function (transformer) {
if (node.isDetached()) {
return; //The node might have been removed from the tree
}
if (!node.isTransformerApplied(transformer)) {
//Check to make sure a transformer of a certain type is only applied once to a node
node.setTransformerApplied(transformer);
//Mark the node as have been transformed by the current transformer
context.setFlag(FLAG_TRANSFORMER_APPLIED);
//Set the current node
context._currentNode = node;
//Set the flag to indicate that a node was transformed
// node.compiler = this;
var transformerFunc = transformer.getFunc();
transformerFunc.call(transformer, node, context); //Have the transformer process the node (NOTE: Just because a node is being processed by the transformer doesn't mean that it has to modify the parse tree)
}
});
} catch (e) {
throw createError(new Error('Unable to compile template at path "' + context.filename + '". Error: ' + e.message), e);
}
}
function transformTreeHelper(node, context) {
transformNode(node, context);
/*
* Now process the child nodes by looping over the child nodes
* and transforming the subtree recursively
*
* NOTE: The length of the childNodes array might change as the tree is being performed.
* The checks to prevent transformers from being applied multiple times makes
* sure that this is not a problem.
*/
node.forEachChild(function (childNode) {
transformTreeHelper(childNode, context);
});
}
function transformTree(rootNode, context) {
context.taglibLookup.forEachTemplateTransformer((transformer) => {
var transformFunc = transformer.getFunc();
rootNode = transformFunc(rootNode, context) || rootNode;
});
/*
* The tree is continuously transformed until we go through an entire pass where
* there were no new nodes that needed to be transformed. This loop makes sure that
* nodes added by transformers are also transformed.
*/
do {
context.clearFlag(FLAG_TRANSFORMER_APPLIED);
//Reset the flag to indicate that no transforms were yet applied to any of the nodes for this pass
transformTreeHelper(rootNode, context); //Run the transforms on the tree
} while (context.isFlagSet(FLAG_TRANSFORMER_APPLIED));
return rootNode;
}
function handleErrors(context) {
// If there were any errors then compilation failed.
if (context.hasErrors()) {
var errors = context.getErrors();
var message = 'An error occurred while trying to compile template at path "' + context.filename + '". Error(s) in template:\n';
for (var i = 0, len = errors.length; i < len; i++) {
let error = errors[i];
message += (i + 1) + ') ' + error.toString() + '\n';
}
var error = new Error(message);
error.errors = errors;
throw error;
}
}
class CompiledTemplate {
constructor(ast, context, codeGenerator) {
this.ast = ast;
this.context = context;
this.filename = context.filename;
}
get dependencies() {
var meta = this.context.meta;
if (meta) {
var root = path.dirname(this.filename);
return (meta.deps || []).map(dep => resolveDep(dep, root));
} else {
return [];
}
}
get code() {
// STAGE 3: Generate the code using the final AST
handleErrors(this.context);
// console.log(module.id, 'FINAL AST:' + JSON.stringify(finalAST, null, 4));
var codeWriter = new CodeWriter(this.context.options, this.context.builder);
codeWriter.write(this.ast);
handleErrors(this.context);
// Return the generated code as the compiled output:
var compiledSrc = codeWriter.getCode();
return compiledSrc;
}
}
class Compiler {
constructor(options, userOptions, inline) {
ok(options, '"options" is required');
this.builder = options.builder;
this.parser = options.parser;
ok(this.builder, '"options.builder" is required');
ok(this.parser, '"options.parser" is required');
}
compile(src, context) {
ok(typeof src === 'string', '"src" argument should be a string');
var codeGenerator = new CodeGenerator(context);
// STAGE 1: Parse the template to produce the initial AST
var ast = this.parser.parse(src, context);
context._parsingFinished = true;
if (context.unrecognizedTags) {
for(let i=0; i<context.unrecognizedTags.length; i++) {
let unrecognizedTag = context.unrecognizedTags[i];
// See if the tag is a macro
if (!context.isMacro(unrecognizedTag.tagName)) {
context.addErrorUnrecognizedTag(unrecognizedTag.tagName, unrecognizedTag.node);
}
}
}
handleErrors(context);
context.root = ast;
// console.log('ROOT', JSON.stringify(ast, null, 2));
// STAGE 2: Transform the initial AST to produce the final AST
var transformedAST = transformTree(ast, context);
// console.log('transformedAST', JSON.stringify(ast, null, 2));
handleErrors(context);
var finalAST = codeGenerator.generateCode(transformedAST);
handleErrors(context);
return new CompiledTemplate(finalAST, context);
}
}
module.exports = Compiler;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | 1 2 1 | 'use strict';
var htmljs = require('htmljs-parser');
class HtmlJsParser {
constructor(options) {
this.ignorePlaceholders = options && options.ignorePlaceholders === true;
}
parse(src, handlers, filename) {
var listeners = {
onText(event) {
handlers.handleCharacters(event.value, event.parseMode);
},
onPlaceholder(event) {
if (event.withinBody) {
if (!event.withinString) {
handlers.handleBodyTextPlaceholder(event.value, event.escape);
}
} else if (event.withinOpenTag) {
// Don't escape placeholder for dynamic attributes. For example: <div ${data.myAttrs}></div>
} else {
// placeholder within attribute
if (event.escape) {
event.value = '$escapeXml(' + event.value + ')';
} else {
event.value = '$noEscapeXml(' + event.value + ')';
}
}
// placeholder within content
},
onCDATA(event) {
handlers.handleCharacters(event.value, 'static-text');
},
onOpenTagName(event, parser) {
event.selfClosed = false; // Don't allow self-closed tags
var tagParseOptions = handlers.getTagParseOptions(event);
if (tagParseOptions) {
event.setParseOptions(tagParseOptions);
}
},
onOpenTag(event, parser) {
event.selfClosed = false; // Don't allow self-closed tags
handlers.handleStartElement(event, parser);
var tagParseOptions = handlers.getTagParseOptions(event);
if (tagParseOptions) {
event.setParseOptions(tagParseOptions);
}
},
onCloseTag(event) {
var tagName = event.tagName;
handlers.handleEndElement(tagName);
},
onDocumentType(event) {
// Document type: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd
// NOTE: The value will be all of the text between "<!" and ">""
handlers.handleDocumentType(event.value);
},
onDeclaration(event) {
handlers.handleDeclaration(event.value);
},
onComment(event) {
// Text within XML comment
handlers.handleComment(event.value);
},
onScriptlet(event) {
// <% (code) %> or $ {}
handlers.handleScriptlet(event);
},
onError(event) {
handlers.handleError(event);
}
};
var parser = this.parser = htmljs.createParser(listeners, {
ignorePlaceholders: this.ignorePlaceholders,
isOpenTagOnly: function(tagName) {
return handlers.isOpenTagOnly(tagName);
}
});
parser.parse(src, filename);
}
}
module.exports = HtmlJsParser;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | 1 1 1 1 | 'use strict';
let CodeWriter = require('./CodeWriter');
function fixIndentation(lines) {
let length = lines.length;
let startLine = 0;
let endLine = length;
for (; startLine<length; startLine++) {
let line = lines[startLine];
if (line.trim() !== '') {
break;
}
}
for (; endLine>startLine; endLine--) {
let line = lines[endLine-1];
if (line.trim() !== '') {
break;
}
}
if (endLine === startLine) {
return '';
}
if (startLine !== 0 || endLine !== length) {
lines = lines.slice(startLine, endLine);
}
let firstLine = lines[0];
let indentToRemove = /^\s*/.exec(firstLine)[0];
if (indentToRemove) {
for (let i=0; i<lines.length; i++) {
let line = lines[i];
if (line.startsWith(indentToRemove)) {
lines[i] = line.substring(indentToRemove.length);
}
}
}
return lines.join('\n');
}
function normalizeTemplateSrc(src) {
let lines = src.split(/\r\n|\n\r|\n/);
if (lines.length) {
if (lines[0].trim() === '') {
return fixIndentation(lines);
}
}
return src.trim();
}
class InlineCompiler {
constructor(context, compiler) {
this.context = context;
this.compiler = compiler;
this.builder = context.builder;
context.setInline(true);
}
compile(src) {
src = normalizeTemplateSrc(src);
// console.log('TEMPLATE SRC:>\n' + src + '\n<');
return this.compiler.compile(src, this.context);
}
get staticCode() {
let staticNodes = this.context.getStaticNodes();
if (!staticNodes || staticNodes.length === 0) {
return null;
}
let codeWriter = new CodeWriter(this.context.options, this.builder);
codeWriter.write(staticNodes);
return codeWriter.getCode();
}
}
module.exports = InlineCompiler;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | 1 1 1 1 1 1 1 1 2 2 2 2 2 2 1 | 'use strict';
var ok = require('assert').ok;
var replacePlaceholderEscapeFuncs = require('./util/replacePlaceholderEscapeFuncs');
var extend = require('raptor-util/extend');
var COMPILER_ATTRIBUTE_HANDLERS = {
'preserve-whitespace': function(attr, context) {
context.setPreserveWhitespace(true);
},
'preserve-comments': function(attr, context) {
context.setPreserveComments(true);
}
};
var ieConditionalCommentRegExp = /^\[if [^]*?<!\[endif\]$/;
function isIEConditionalComment(comment) {
return ieConditionalCommentRegExp.test(comment);
}
function mergeShorthandClassNames(el, shorthandClassNames, context) {
var builder = context.builder;
let classNames = shorthandClassNames.map((className) => {
return builder.parseExpression(className.value);
});
var classAttr = el.getAttributeValue('class');
if (classAttr) {
classNames.push(classAttr);
}
let prevClassName;
var finalClassNames = [];
for (var i=0; i<classNames.length; i++) {
let className = classNames[i];
if (prevClassName && className.type === 'Literal' && prevClassName.type === 'Literal') {
prevClassName.value += ' ' + className.value;
} else {
finalClassNames.push(className);
prevClassName = className;
}
}
if (finalClassNames.length === 1) {
el.setAttributeValue('class', finalClassNames[0]);
} else {
el.setAttributeValue(
'class',
builder.functionCall(
context.helper('classList'),
[
builder.literal(finalClassNames)
]));
}
}
function getParserStateForTag(parser, el, tagDef) {
var attributes = el.attributes;
if (attributes) {
for (var i=0; i<attributes.length; i++) {
var attr = attributes[i];
var attrName = attr.name;
if (attrName === 'marko-body') {
var parseMode;
if (attr.literalValue) {
parseMode = attr.literalValue;
}
if (parseMode === 'static-text' ||
parseMode === 'parsed-text' ||
parseMode === 'html') {
return parseMode;
} else {
parser.context.addError({
message: 'Value for "marko-body" should be one of the following: "static-text", "parsed-text", "html"',
code: 'ERR_INVALID_ATTR'
});
return;
}
} else if (attrName === 'template-helpers') {
return 'static-text';
} else if (attrName === 'marko-init') {
return 'static-text';
}
}
}
if (tagDef) {
var body = tagDef.body;
if (body) {
return body; // 'parsed-text' | 'static-text' | 'html'
}
}
return null; // Default parse state
}
class Parser {
constructor(parserImpl, options) {
ok(parserImpl, '"parserImpl" is required');
this.parserImpl = parserImpl;
this.prevTextNode = null;
this.stack = null;
this.raw = options && options.raw === true;
// The context gets provided when parse is called
// but we store it as part of the object so that the handler
// methods have access
this.context = null;
}
_reset() {
this.prevTextNode = null;
this.stack = [];
}
parse(src, context) {
ok(typeof src === 'string', '"src" should be a string');
ok(context, '"context" is required');
this._reset();
this.context = context;
var builder = context.builder;
var rootNode = builder.templateRoot();
this.stack.push({
node: rootNode
});
this.parserImpl.parse(src, this, context.filename);
return rootNode;
}
handleCharacters(text, parseMode) {
var builder = this.context.builder;
var escape = parseMode !== 'html';
// NOTE: If parseMode is 'static-text' or 'parsed-text' then that means that special
// HTML characters may not have been escaped on the way in so we need to escape
// them on the way out
if (this.prevTextNode && this.prevTextNode.isLiteral() && this.prevTextNode.escape === escape) {
this.prevTextNode.argument.value += text;
} else {
this.prevTextNode = builder.text(builder.literal(text), escape);
this.parentNode.appendChild(this.prevTextNode);
}
}
handleStartElement(el, parser) {
var context = this.context;
var builder = context.builder;
var tagName = el.tagName;
var tagNameExpression = el.tagNameExpression;
var attributes = el.attributes;
var argument = el.argument; // e.g. For <for(color in colors)>, argument will be "color in colors"
if (argument) {
argument = argument.value;
}
var raw = this.raw;
if (!raw) {
if (tagNameExpression) {
tagName = builder.parseExpression(tagNameExpression);
} else if (tagName === 'marko-compiler-options') {
this.parentNode.setTrimStartEnd(true);
attributes.forEach(function (attr) {
let attrName = attr.name;
let handler = COMPILER_ATTRIBUTE_HANDLERS[attrName];
if (!handler) {
context.addError({
code: 'ERR_INVALID_COMPILER_OPTION',
message: 'Invalid Marko compiler option of "' + attrName + '". Allowed: ' + Object.keys(COMPILER_ATTRIBUTE_HANDLERS).join(', '),
pos: el.pos,
node: el
});
return;
}
handler(attr, context);
});
return;
}
}
this.prevTextNode = null;
var tagDef = el.tagName ? this.context.getTagDef(el.tagName) : null;
var attributeParseErrors = [];
// <div class="foo"> -> "div class=foo"
var tagString = parser.substring(el.pos, el.endPos)
.replace(/^<|\/>$|>$/g, "").trim();
var shouldParsedAttributes = !tagDef || tagDef.parseAttributes !== false;
var parsedAttributes = [];
if (shouldParsedAttributes) {
attributes.forEach((attr) => {
var attrValue;
if (attr.hasOwnProperty('literalValue')) {
attrValue = builder.literal(attr.literalValue);
} else if (attr.value == null) {
attrValue = undefined;
} else {
let parsedExpression;
let valid = true;
try {
parsedExpression = builder.parseExpression(attr.value);
} catch(e) {
if (shouldParsedAttributes) {
valid = false;
attributeParseErrors.push('Invalid JavaScript expression for attribute "' + attr.name + '": ' + e);
} else {
// Attribute failed to parse. Skip it...
return;
}
}
if (valid) {
if (raw) {
attrValue = parsedExpression;
} else {
attrValue = replacePlaceholderEscapeFuncs(parsedExpression, context);
}
} else {
attrValue = null;
}
}
var attrDef = {
name: attr.name,
value: attrValue,
rawValue: attr.value
};
if (attr.argument) {
// TODO Do something with the argument pos
attrDef.argument = attr.argument.value;
}
parsedAttributes.push(attrDef);
});
}
var elDef = {
tagName: tagName,
argument: argument,
tagString,
openTagOnly: el.openTagOnly === true,
selfClosed: el.selfClosed === true,
pos: el.pos,
attributes: parsedAttributes
};
var node;
if (raw) {
node = builder.htmlElement(elDef);
node.pos = elDef.pos;
node.tagDef = tagDef;
} else {
node = this.context.createNodeForEl(elDef);
}
if (attributeParseErrors.length) {
attributeParseErrors.forEach((e) => {
context.addError(node, e);
});
}
if (raw) {
if (el.shorthandId) {
let parsed = builder.parseExpression(el.shorthandId.value);
node.rawShorthandId = parsed.value;
}
if (el.shorthandClassNames) {
node.rawShorthandClassNames = el.shorthandClassNames.map((className) => {
let parsed = builder.parseExpression(className.value);
return parsed.value;
});
}
} else {
if (el.shorthandClassNames) {
mergeShorthandClassNames(node, el.shorthandClassNames, context);
}
if (el.shorthandId) {
if (node.hasAttribute('id')) {
context.addError(node, 'A shorthand ID cannot be used in conjunction with the "id" attribute');
} else {
node.setAttributeValue('id', builder.parseExpression(el.shorthandId.value));
}
}
}
this.parentNode.appendChild(node);
this.stack.push({
node: node,
tag: null
});
}
handleEndElement(elementName) {
if (this.raw !== true) {
if (elementName === 'marko-compiler-options') {
return;
}
}
this.prevTextNode = null;
this.stack.pop();
}
handleComment(comment) {
this.prevTextNode = null;
var builder = this.context.builder;
var preserveComment = this.context.isPreserveComments() ||
isIEConditionalComment(comment);
if (this.raw || preserveComment) {
var commentNode = builder.htmlComment(builder.literal(comment));
this.parentNode.appendChild(commentNode);
}
}
handleDeclaration(value) {
this.prevTextNode = null;
var builder = this.context.builder;
var declarationNode = builder.declaration(builder.literal(value));
this.parentNode.appendChild(declarationNode);
}
handleDocumentType(value) {
this.prevTextNode = null;
var builder = this.context.builder;
var docTypeNode = builder.documentType(builder.literal(value));
this.parentNode.appendChild(docTypeNode);
}
handleBodyTextPlaceholder(expression, escape) {
this.prevTextNode = null;
var builder = this.context.builder;
var parsedExpression = builder.parseExpression(expression);
var preserveWhitespace = true;
var text = builder.text(parsedExpression, escape, preserveWhitespace);
this.parentNode.appendChild(text);
}
handleScriptlet(event) {
this.prevTextNode = null;
var builder = this.context.builder;
var scriptlet = builder.scriptlet(event);
this.parentNode.appendChild(scriptlet);
}
handleError(event) {
this.context.addError({
message: event.message,
code: event.code,
pos: event.pos,
endPos: event.endPos
});
}
get parentNode() {
var last = this.stack[this.stack.length-1];
return last.node;
}
getTagParseOptions(el) {
var tagName = el.tagName;
var tagDef = this.context.getTagDef(tagName);
var state = getParserStateForTag(this, el, tagDef);
var parseOptions = tagDef && tagDef.parseOptions;
if (!state && !parseOptions) {
return;
}
if (parseOptions) {
if (state) {
// We need to merge in the state to the returned parse options
parseOptions = extend({ state: state }, parseOptions);
}
} else {
parseOptions = { state: state };
}
return parseOptions;
}
isOpenTagOnly(tagName) {
var tagDef = this.context.getTagDef(tagName);
return tagDef && tagDef.openTagOnly;
}
}
module.exports = Parser;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | 1 1 1 1 | 'use strict';
var isArray = Array.isArray;
var Container = require('./ast/Container');
function noop() {}
class Walker {
constructor(options) {
this._enter = options.enter || noop;
this._exit = options.exit || noop;
this._enterArray = options.enterArray || noop;
this._exitArray = options.exitArray || noop;
this._stopped = false;
this._reset();
this._stack = [];
}
_reset() {
this._skipped = false;
this._replaced = undefined;
this._removed = false;
}
skip() {
this._skipped = true;
}
stop() {
this._stopped = true;
}
replace(newNode) {
this._replaced = newNode;
}
remove() {
this._removed = true;
}
_walkArray(array) {
var hasRemoval = false;
array = this._enterArray(array) || array;
array.forEach((node, i) => {
var transformed = this.walk(node);
if (transformed == null) {
array[i] = null;
hasRemoval = true;
} else if (transformed !== node) {
array[i] = transformed;
}
});
if (hasRemoval) {
for (let i=array.length-1; i>=0; i--) {
if (array[i] == null) {
array.splice(i, 1);
}
}
}
array = this._exitArray(array) || array;
return array;
}
_walkContainer(nodes) {
nodes.forEach((node) => {
var transformed = this.walk(node);
if (!transformed) {
node.container.removeChild(node);
} else if (transformed !== node) {
node.container.replaceChild(transformed, node);
}
});
}
walk(node) {
if (!node || this._stopped || typeof node === 'string') {
return node;
}
this._reset();
var parent = this._stack.length ? this._stack[this._stack.length - 1] : undefined;
this._stack.push(node);
var replaced = this._enter(node, parent);
if (replaced === undefined) {
replaced = this._replaced;
}
if (this._removed) {
replaced = null;
}
if (replaced !== undefined) {
this._stack.pop();
return replaced;
}
if (this._skipped || this._stopped) {
this._stack.pop();
return node;
}
if (isArray(node)) {
let array = node;
let newArray = this._walkArray(array);
this._stack.pop();
return newArray;
} else if (node instanceof Container) {
let container = node;
this._walkContainer(container);
this._stack.pop();
return container;
} else {
if (node.walk) {
node.walk(this);
}
}
if (this._stopped) {
this._stack.pop();
return node;
}
this._reset();
replaced = this._exit(node, parent);
if (replaced === undefined) {
replaced = this._replaced;
}
if (this._removed) {
replaced = null;
}
if (replaced !== undefined) {
this._stack.pop();
return replaced;
}
this._stack.pop();
return node;
}
}
module.exports = Walker;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | 1 1 1 1 1 1 | var NODE_ENV = process.env.NODE_ENV; var config; /* globals window */ var g = typeof window === 'undefined' ? global : window; Iif (g.__MARKO_CONFIG) { config = g.__MARKO_CONFIG; } else { config = g.__MARKO_CONFIG = { /** * If true, then the compiler will check the disk to see if a previously compiled * template is the same age or newer than the source template. If so, the previously * compiled template will be loaded. Otherwise, the template will be recompiled * and saved to disk. * * If false, the template will always be recompiled. If `writeToDisk` is false * then this option will be ignored. */ checkUpToDate: process.env.MARKO_CLEAN ? false : true, /** * If true (the default) then compiled templates will be written to disk. If false, * compiled templates will not be written to disk (i.e., no `.marko.js` file will * be generated) */ writeToDisk: true, /** * If true, then the compiled template on disk will assumed to be up-to-date if it exists. */ assumeUpToDate: process.env.MARKO_CLEAN != null || process.env.hasOwnProperty('MARKO_HOT_RELOAD') ? false : ( NODE_ENV == null ? false : (NODE_ENV !== 'development' && NODE_ENV !== 'dev')), /** * If true, whitespace will be preserved in templates. Defaults to false. * @type {Boolean} */ preserveWhitespace: false, // The default output mode for compiled templates output: 'html', /** * Whether the version should be written to the template as a comment e.g. * // Compiled using marko@4.0.0 - DO NOT EDIT */ writeVersionComment: true }; } module.exports = config; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 7 7 1 1 1 1 1 1 1 1 1 | 'use strict';
var Compiler = require('./Compiler');
var Walker = require('./Walker');
var Parser = require('./Parser');
var HtmlJsParser = require('./HtmlJsParser');
var Builder = require('./Builder');
var extend = require('raptor-util/extend');
var CompileContext = require('./CompileContext');
var globalConfig = require('./config');
var CompileContext = require('./CompileContext');
var InlineCompiler = require('./InlineCompiler');
var ok = require('assert').ok;
var fs = require('fs');
var taglibLoader = require('./taglib-loader');
var defaults = extend({}, globalConfig);
Object.defineProperty(exports, 'defaultOptions', {
get: function() { return globalConfig; },
enumerable: true,
configurable: false
});
Object.defineProperty(exports, 'config', {
get: function() { return globalConfig; },
enumerable: true,
configurable: false
});
var defaultParser = new Parser(new HtmlJsParser());
var rawParser = new Parser(
new HtmlJsParser({
ignorePlaceholders: true
}),
{
raw: true
});
function configure(newConfig) {
if (!newConfig) {
newConfig = {};
}
extend(globalConfig, defaults);
extend(globalConfig, newConfig);
}
var defaultCompiler = new Compiler({
parser: defaultParser,
builder: Builder.DEFAULT_BUILDER
});
function createBuilder(options) {
return new Builder(options);
}
function createWalker(options) {
return new Walker(options);
}
function _compile(src, filename, userOptions, callback) {
ok(filename, '"filename" argument is required');
ok(typeof filename === 'string', '"filename" argument should be a string');
var options = {};
extend(options, globalConfig);
if (userOptions) {
extend(options, userOptions);
}
var compiler = defaultCompiler;
var context = new CompileContext(src, filename, compiler.builder, options);
if (callback) {
let compiled;
try {
compiled = compiler.compile(src, context);
} catch(e) {
return callback(e);
}
callback(null, userOptions.sourceOnly ? compiled.code : compiled);
} else {
let compiled = compiler.compile(src, context);
return userOptions.sourceOnly ? compiled.code : compiled;
}
}
function compile(src, filename, options, callback) {
if (typeof options === 'function') {
callback = options;
options = null;
}
options = options || {};
options.sourceOnly = options.sourceOnly !== false;
return _compile(src, filename, options, callback);
}
function compileForBrowser(src, filename, options, callback) {
if (typeof options === 'function') {
callback = options;
options = null;
}
options = extend({output: 'vdom', meta: false, browser: true, sourceOnly: false}, options);
return compile(src, filename, options, callback);
}
function compileFile(filename, options, callback) {
if (typeof options === 'function') {
callback = options;
options = null;
}
options = options || {};
options.sourceOnly = options.sourceOnly !== false;
if (callback) {
fs.readFile(filename, {encoding: 'utf8'}, function(err, templateSrc) {
if (err) {
return callback(err);
}
_compile(templateSrc, filename, options, callback);
});
} else {
let templateSrc = fs.readFileSync(filename, {encoding: 'utf8'});
return _compile(templateSrc, filename, options, callback);
}
}
function compileFileForBrowser(filename, options, callback) {
if (typeof options === 'function') {
callback = options;
options = null;
}
options = extend({output: 'vdom', meta: false, browser: true, sourceOnly: false}, options);
return compileFile(filename, options, callback);
}
function createInlineCompiler(filename, userOptions) {
var options = {};
extend(options, globalConfig);
if (userOptions) {
extend(options, userOptions);
}
var compiler = defaultCompiler;
var context = new CompileContext('', filename, compiler.builder, options);
return new InlineCompiler(context, compiler);
}
function checkUpToDate(templateFile, templateJsFile) {
return false; // TODO Implement checkUpToDate
}
function getLastModified(path, options, callback) {
if (typeof options === 'function') {
callback = options;
options = null;
}
callback(null, -1); // TODO Implement getLastModified
}
function clearCaches() {
exports.taglibLookup.clearCache();
exports.taglibFinder.clearCache();
exports.taglibLoader.clearCache();
}
function parseRaw(templateSrc, filename) {
var context = new CompileContext(templateSrc, filename, Builder.DEFAULT_BUILDER);
var parsed = rawParser.parse(templateSrc, context);
if (context.hasErrors()) {
var errors = context.getErrors();
var message = 'An error occurred while trying to compile template at path "' + filename + '". Error(s) in template:\n';
for (var i = 0, len = errors.length; i < len; i++) {
let error = errors[i];
message += (i + 1) + ') ' + error.toString() + '\n';
}
var error = new Error(message);
error.errors = errors;
throw error;
}
return parsed;
}
exports.createBuilder = createBuilder;
exports.compileFile = compileFile;
exports.compile = compile;
exports.compileForBrowser = compileForBrowser;
exports.compileFileForBrowser = compileFileForBrowser;
exports.parseRaw = parseRaw;
exports.createInlineCompiler = createInlineCompiler;
exports.checkUpToDate = checkUpToDate;
exports.getLastModified = getLastModified;
exports.createWalker = createWalker;
exports.builder = Builder.DEFAULT_BUILDER;
exports.configure = configure;
exports.clearCaches = clearCaches;
var taglibLookup = require('./taglib-lookup');
exports.taglibLookup = taglibLookup;
exports.taglibLoader = taglibLoader;
exports.taglibFinder = require('./taglib-finder');
function buildTaglibLookup(dirname) {
return taglibLookup.buildLookup(dirname);
}
exports.buildTaglibLookup = buildTaglibLookup;
function registerTaglib(taglibProps, taglibPath) {
var taglib = taglibLoader.createTaglib(taglibPath);
taglibLoader.loadTaglibFromProps(taglib, taglibProps);
taglibLookup.registerTaglib(taglib);
}
registerTaglib(require('../taglibs/core/marko.json'), require.resolve('../taglibs/core/marko.json'));
registerTaglib(require('../taglibs/layout/marko.json'), require.resolve('../taglibs/layout/marko.json'));
registerTaglib(require('../taglibs/html/marko.json'), require.resolve('../taglibs/html/marko.json'));
registerTaglib(require('../taglibs/svg/marko.json'), require.resolve('../taglibs/svg/marko.json'));
registerTaglib(require('../taglibs/async/marko.json'), require.resolve('../taglibs/async/marko.json'));
registerTaglib(require('../taglibs/cache/marko.json'), require.resolve('../taglibs/cache/marko.json'));
registerTaglib(require('../components/taglib/marko.json'), require.resolve('../components/taglib/marko.json'));
exports.registerTaglib = function(filePath) {
ok(typeof filePath === 'string', '"filePath" shouldbe a string');
var taglib = taglibLoader.loadTaglibFromFile(filePath);
taglibLookup.registerTaglib(taglib);
clearCaches();
};
exports.isVDOMSupported = true;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 1 1 1 1 1 1 1 45 1 | var nativeRequire = require;
var resolveFrom = require('resolve-from');
var deresolve = require('./util/deresolve');
const deresolveOptions = {
shouldRemoveExt(ext) {
return ext === '.js' || ext === '.json' || ext === '.es6';
}
};
// This allows us to swap out a different implementation in the browser...
// We only need this to make Try Online work :/
exports.require = function(path) {
return nativeRequire(path);
};
exports.resolve = function(path) {
return nativeRequire.resolve(path);
};
exports.resolveFrom = function(from, target) {
return resolveFrom(from, target);
};
exports.deresolve = function(targetFilename, from) {
return deresolve(targetFilename, from, deresolveOptions);
};
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| ArrayContainer.js | 3.74% | (4 / 107) | 0% | (0 / 42) | 0% | (0 / 16) | 3.74% | (4 / 107) | |
| ArrayExpression.js | 6.06% | (2 / 33) | 0% | (0 / 10) | 0% | (0 / 6) | 6.06% | (2 / 33) | |
| Assignment.js | 5.71% | (2 / 35) | 0% | (0 / 14) | 0% | (0 / 7) | 5.71% | (2 / 35) | |
| AttributePlaceholder.js | 18.18% | (2 / 11) | 100% | (0 / 0) | 0% | (0 / 6) | 18.18% | (2 / 11) | |
| BinaryExpression.js | 8.2% | (5 / 61) | 0% | (0 / 32) | 0% | (0 / 9) | 8.2% | (5 / 61) | |
| Code.js | 27.27% | (3 / 11) | 0% | (0 / 2) | 0% | (0 / 3) | 27.27% | (3 / 11) | |
| Comment.js | 23.08% | (3 / 13) | 0% | (0 / 4) | 0% | (0 / 5) | 23.08% | (3 / 13) | |
| ConditionalExpression.js | 7.41% | (2 / 27) | 100% | (0 / 0) | 0% | (0 / 7) | 7.41% | (2 / 27) | |
| Container.js | 33.33% | (1 / 3) | 100% | (0 / 0) | 0% | (0 / 2) | 33.33% | (1 / 3) | |
| ContainerNode.js | 33.33% | (2 / 6) | 100% | (0 / 0) | 0% | (0 / 3) | 33.33% | (2 / 6) | |
| CustomTag.js | 4.37% | (15 / 343) | 0% | (0 / 207) | 0% | (0 / 24) | 4.37% | (15 / 343) | |
| Declaration.js | 28.57% | (2 / 7) | 100% | (0 / 0) | 0% | (0 / 3) | 28.57% | (2 / 7) | |
| DocumentType.js | 25% | (2 / 8) | 100% | (0 / 0) | 0% | (0 / 4) | 25% | (2 / 8) | |
| Else.js | 14.29% | (2 / 14) | 0% | (0 / 2) | 0% | (0 / 4) | 14.29% | (2 / 14) | |
| ElseIf.js | 14.29% | (2 / 14) | 0% | (0 / 2) | 0% | (0 / 3) | 14.29% | (2 / 14) | |
| Expression.js | 30% | (3 / 10) | 100% | (0 / 0) | 0% | (0 / 5) | 30% | (3 / 10) | |
| ForEach.js | 5.77% | (3 / 52) | 0% | (0 / 14) | 0% | (0 / 3) | 5.77% | (3 / 52) | |
| ForEachProp.js | 8.11% | (3 / 37) | 0% | (0 / 8) | 0% | (0 / 3) | 8.11% | (3 / 37) | |
| ForRange.js | 13.89% | (5 / 36) | 0% | (0 / 16) | 0% | (0 / 3) | 13.89% | (5 / 36) | |
| ForStatement.js | 6.25% | (2 / 32) | 0% | (0 / 6) | 0% | (0 / 4) | 6.25% | (2 / 32) | |
| FunctionCall.js | 7.84% | (4 / 51) | 0% | (0 / 26) | 0% | (0 / 5) | 7.84% | (4 / 51) | |
| FunctionDeclaration.js | 7.32% | (3 / 41) | 0% | (0 / 18) | 0% | (0 / 5) | 7.32% | (3 / 41) | |
| Html.js | 9.76% | (4 / 41) | 0% | (0 / 20) | 0% | (0 / 6) | 9.76% | (4 / 41) | |
| HtmlAttributeCollection.js | 5.8% | (4 / 69) | 0% | (0 / 31) | 0% | (0 / 14) | 5.8% | (4 / 69) | |
| HtmlComment.js | 18.18% | (2 / 11) | 100% | (0 / 0) | 0% | (0 / 4) | 18.18% | (2 / 11) | |
| Identifier.js | 50% | (4 / 8) | 50% | (1 / 2) | 25% | (1 / 4) | 50% | (4 / 8) | |
| If.js | 5.56% | (3 / 54) | 0% | (0 / 16) | 0% | (0 / 6) | 5.56% | (3 / 54) | |
| InvokeMacro.js | 5.97% | (4 / 67) | 0% | (0 / 28) | 0% | (0 / 4) | 5.97% | (4 / 67) | |
| Literal.js | 9.33% | (7 / 75) | 0% | (0 / 44) | 16.67% | (1 / 6) | 9.33% | (7 / 75) | |
| LogicalExpression.js | 10.87% | (5 / 46) | 0% | (0 / 16) | 0% | (0 / 9) | 10.87% | (5 / 46) | |
| Macro.js | 16.67% | (3 / 18) | 0% | (0 / 4) | 0% | (0 / 3) | 16.67% | (3 / 18) | |
| MemberExpression.js | 10.26% | (4 / 39) | 0% | (0 / 8) | 0% | (0 / 6) | 10.26% | (4 / 39) | |
| NewExpression.js | 6% | (3 / 50) | 0% | (0 / 22) | 0% | (0 / 7) | 6% | (3 / 50) | |
| Node.js | 12.15% | (22 / 181) | 0% | (0 / 92) | 2.33% | (1 / 43) | 12.15% | (22 / 181) | |
| ObjectExpression.js | 5.88% | (2 / 34) | 0% | (0 / 12) | 0% | (0 / 6) | 5.88% | (2 / 34) | |
| Program.js | 25% | (2 / 8) | 100% | (0 / 0) | 0% | (0 / 4) | 25% | (2 / 8) | |
| Property.js | 10% | (3 / 30) | 0% | (0 / 8) | 0% | (0 / 6) | 10% | (3 / 30) | |
| Return.js | 14.29% | (2 / 14) | 0% | (0 / 4) | 0% | (0 / 4) | 14.29% | (2 / 14) | |
| Scriptlet.js | 21.43% | (3 / 14) | 0% | (0 / 2) | 0% | (0 / 3) | 21.43% | (3 / 14) | |
| SelfInvokingFunction.js | 11.11% | (2 / 18) | 0% | (0 / 4) | 0% | (0 / 3) | 11.11% | (2 / 18) | |
| SequenceExpression.js | 9.52% | (2 / 21) | 0% | (0 / 4) | 0% | (0 / 7) | 9.52% | (2 / 21) | |
| TemplateRoot.js | 6.67% | (4 / 60) | 0% | (0 / 22) | 0% | (0 / 8) | 6.67% | (4 / 60) | |
| ThisExpression.js | 33.33% | (2 / 6) | 100% | (0 / 0) | 0% | (0 / 4) | 33.33% | (2 / 6) | |
| UnaryExpression.js | 6.82% | (3 / 44) | 0% | (0 / 24) | 0% | (0 / 7) | 6.82% | (3 / 44) | |
| UpdateExpression.js | 7.5% | (3 / 40) | 0% | (0 / 16) | 0% | (0 / 7) | 7.5% | (3 / 40) | |
| VariableDeclarator.js | 14.81% | (4 / 27) | 0% | (0 / 10) | 0% | (0 / 4) | 14.81% | (4 / 27) | |
| Vars.js | 5.88% | (2 / 34) | 0% | (0 / 22) | 0% | (0 / 5) | 5.88% | (2 / 34) | |
| WhileStatement.js | 11.76% | (2 / 17) | 100% | (0 / 0) | 0% | (0 / 4) | 11.76% | (2 / 17) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | 1 1 1 1 | 'use strict';
var ok = require('assert').ok;
var isArray = Array.isArray;
var Container = require('./Container');
class ArrayContainer extends Container {
constructor(node, array) {
super(node);
this.items = array;
}
forEach(callback, thisObj) {
var array = this.array.concat([]);
for (var i=0; i<array.length; i++) {
var item = array[i];
if (item.container === this) {
callback.call(thisObj, item, i);
}
}
}
replaceChild(newChild, oldChild) {
ok(newChild, '"newChild" is required"');
var array = this.array;
var len = array.length;
for (var i=0; i<len; i++) {
var curChild = array[i];
if (curChild === oldChild) {
array[i] = newChild;
oldChild.detach();
newChild.container = this;
return true;
}
}
return false;
}
removeChild(child) {
var childIndex = this.array.indexOf(child);
if (childIndex !== -1) {
this.array.splice(childIndex, 1);
child.detach();
return true;
} else {
return false;
}
}
prependChild(newChild) {
ok(newChild, '"newChild" is required"');
this.array.unshift(newChild);
newChild.container = this;
}
appendChild(newChild) {
ok(newChild, '"newChild" is required"');
newChild.detach();
this.array.push(newChild);
newChild.container = this;
}
insertChildBefore(newChild, referenceNode) {
ok(newChild, '"newChild" is required"');
ok(referenceNode, 'Invalid reference child');
var array = this.array;
var len = array.length;
for (var i=0; i<len; i++) {
var curChild = array[i];
if (curChild === referenceNode) {
array.splice(i, 0, newChild);
newChild.container = this;
return;
}
}
throw new Error('Reference node not found');
}
insertChildAfter(newChild, referenceNode) {
ok(newChild, '"newChild" is required"');
ok(referenceNode, 'Invalid reference child');
var array = this.array;
var len = array.length;
for (var i=0; i<len; i++) {
var curChild = array[i];
if (curChild === referenceNode) {
array.splice(i+1, 0, newChild);
newChild.container = this;
return;
}
}
throw new Error('Reference node not found');
}
moveChildrenTo(target) {
ok(target.appendChild, 'Node does not support appendChild(node): ' + target);
var array = this.array;
var len = array.length;
for (var i=0; i<len; i++) {
var curChild = array[i];
curChild.container = null; // Detach the child from this container
target.appendChild(curChild);
}
this.array.length = 0; // Clear out this container
}
getPreviousSibling(node) {
if (node.container !== this) {
throw new Error('Node does not belong to container: ' + node);
}
var array = this.array;
for (var i=0; i<array.length; i++) {
var curNode = array[i];
if (curNode.container !== this) {
continue;
}
if (curNode === node) {
return i-1 >= 0 ? array[i-1] : undefined;
}
}
}
getNextSibling(node) {
if (node.container !== this) {
throw new Error('Node does not belong to container: ' + node);
}
var array = this.array;
for (var i=0; i<array.length; i++) {
var curNode = array[i];
if (curNode.container !== this) {
continue;
}
if (curNode === node) {
return i+1 < array.length ? array[i+1] : undefined;
}
}
}
forEachNextSibling(node, callback, thisObj) {
if (node.container !== this) {
throw new Error('Node does not belong to container: ' + node);
}
var array = this.array.concat([]);
var found = false;
for (var i=0; i<array.length; i++) {
var curNode = array[i];
if (curNode.container !== this) {
continue;
}
if (found) {
if (curNode.container === this) {
var keepGoing = callback.call(thisObj, curNode) !== false;
if (!keepGoing) {
return;
}
}
} else if (curNode === node) {
found = true;
continue;
}
}
}
get firstChild() {
return this.array[0];
}
get length() {
return this.array.length;
}
get items() {
return this.array;
}
set items(newItems) {
if (newItems) {
ok(isArray(newItems), 'Invalid array');
for (let i=0; i<newItems.length; i++) {
newItems[i].container = this;
}
}
this.array = newItems || [];
}
}
module.exports = ArrayContainer;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | 1 1 | 'use strict';
var Node = require('./Node');
class ArrayExpression extends Node {
constructor(def) {
super('ArrayExpression');
this.elements = def.elements;
}
generateCode(codegen) {
this.elements = codegen.generateCode(this.elements);
return this;
}
writeCode(writer) {
var elements = this.elements;
if (!elements || !elements.length) {
writer.write('[]');
return;
}
writer.incIndent();
writer.write('[\n');
writer.incIndent();
elements.forEach((element, i) => {
writer.writeLineIndent();
writer.write(element);
if (i < elements.length - 1) {
writer.write(',\n');
} else {
writer.write('\n');
}
});
writer.decIndent();
writer.writeLineIndent();
writer.write(']');
writer.decIndent();
}
walk(walker) {
this.elements = walker.walk(this.elements);
}
toJSON() {
return {
type: 'ArrayExpression',
elements: this.elements
};
}
toString() {
var result = '[';
var elements = this.elements;
if (elements) {
elements.forEach((element, i) => {
if (i !== 0) {
result += ', ';
}
result += element.toString();
});
}
return result + ']';
}
}
module.exports = ArrayExpression;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | 1 1 | 'use strict';
var Node = require('./Node');
class Assignment extends Node {
constructor(def) {
super('Assignment');
this.left = def.left;
this.right = def.right;
this.operator = def.operator;
}
generateCode(codegen) {
this.left = codegen.generateCode(this.left);
this.right = codegen.generateCode(this.right);
return this;
}
writeCode(writer) {
var left = this.left;
var right = this.right;
var operator = this.operator;
writer.write(left);
writer.write(' ' + (operator || '=') + ' ');
var wrap = right instanceof Assignment;
if (wrap) {
writer.write('(');
}
writer.write(right);
if (wrap) {
writer.write(')');
}
}
walk(walker) {
this.left = walker.walk(this.left);
this.right = walker.walk(this.right);
}
isCompoundExpression() {
return true;
}
/**
* "noOutput" should be true if the Node.js does not result in any HTML or Text output
*/
get noOutput() {
return !(this.body && this.body.length);
}
toString() {
var left = this.left;
var right = this.right;
var operator = this.operator;
var result = left.toString() + ' ' + (operator || '=') + ' ';
var wrap = right instanceof Assignment;
if (wrap) {
result += '(';
}
result += right.toString();
if (wrap) {
result += ')';
}
return result;
}
}
module.exports = Assignment;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 1 1 | 'use strict';
var Node = require('./Node');
class AttributePlaceholder extends Node {
constructor(def) {
super('AttributePlaceholder');
this.value = def.value;
this.escape = def.escape;
}
generateCode(codegen) {
this.value = codegen.generateCode(this.value);
return this;
}
writeCode(writer) {
writer.write(this.value);
}
walk(walker) {
this.value = walker.walk(this.value);
}
isCompoundExpression() {
return this.value.isCompoundExpression();
}
/**
* "noOutput" should be true if the Node.js does not result in any HTML or Text output
*/
get noOutput() {
return this.value.noOutput;
}
}
module.exports = AttributePlaceholder;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | 1 1 1 1 1 | 'use strict';
var Node = require('./Node');
var isCompoundExpression = require('../util/isCompoundExpression');
function writeCodeForOperand(node, writer) {
var wrap = isCompoundExpression(node);
if (wrap) {
writer.write('(');
}
writer.write(node);
if (wrap) {
writer.write(')');
}
}
function operandToString(node) {
var wrap = isCompoundExpression(node);
var result = '';
if (wrap) {
result += '(';
}
result += node.toString();
if (wrap) {
result += ')';
}
return result;
}
class BinaryExpression extends Node {
constructor(def) {
super('BinaryExpression');
this.left = def.left;
this.operator = def.operator;
this.right = def.right;
}
generateCode(codegen) {
this.left = codegen.generateCode(this.left);
this.right = codegen.generateCode(this.right);
var left = this.left;
var right = this.right;
var operator = this.operator;
if (!left || !right) {
throw new Error('Invalid BinaryExpression: ' + this);
}
var builder = codegen.builder;
if (left.type === 'Literal' && right.type === 'Literal') {
if (operator === '+') {
return builder.literal(left.value + right.value);
} else if (operator === '-') {
return builder.literal(left.value - right.value);
} else if (operator === '*') {
return builder.literal(left.value * right.value);
} else if (operator === '/') {
return builder.literal(left.value / right.value);
}
}
return this;
}
writeCode(writer) {
var left = this.left;
var operator = this.operator;
var right = this.right;
if (!left || !right) {
throw new Error('Invalid BinaryExpression: ' + this);
}
writeCodeForOperand(left, writer);
writer.write(' ');
writer.write(operator);
writer.write(' ');
writeCodeForOperand(right, writer);
}
isCompoundExpression() {
return true;
}
toJSON() {
return {
type: 'BinaryExpression',
left: this.left,
operator: this.operator,
right: this.right
};
}
walk(walker) {
this.left = walker.walk(this.left);
this.right = walker.walk(this.right);
}
toString() {
var left = this.left;
var operator = this.operator;
var right = this.right;
if (!left || !right) {
throw new Error('Invalid BinaryExpression: ' + this);
}
return operandToString(left) + ' ' + operator + ' ' + operandToString(right);
}
}
module.exports = BinaryExpression;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 1 1 1 | 'use strict';
var Node = require('./Node');
var adjustIndent = require('../util/adjustIndent');
class Code extends Node {
constructor(def) {
super('Code');
this.value = def.value;
}
generateCode(codegen) {
return this;
}
writeCode(writer) {
var code = this.value;
if (!code) {
return;
}
code = adjustIndent(code, writer.currentIndent);
writer.write(code);
}
}
module.exports = Code;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 1 1 1 | 'use strict';
const Node = require('./Node');
function _isMultilineComment(comment) {
return comment && comment.indexOf('\n') !== -1;
}
class Comment extends Node {
constructor(def) {
super('Comment');
const comment = def.comment;
if (_isMultilineComment(comment)) {
this.comment = `/*\n${comment}\n*/`;
} else {
this.comment = `// ${comment}`;
}
}
generateCode(codegen) {
return this;
}
writeCode(writer) {
var name = this.comment;
writer.write(name);
}
toString() {
return this.comment;
}
}
module.exports = Comment;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | 1 1 | 'use strict';
var Node = require('./Node');
class ConditionalExpression extends Node {
constructor(def) {
super('ConditionalExpression');
this.test = def.test;
this.consequent = def.consequent;
this.alternate = def.alternate;
}
generateCode(codegen) {
this.test = codegen.generateCode(this.test);
this.consequent = codegen.generateCode(this.consequent);
this.alternate = codegen.generateCode(this.alternate);
return this;
}
writeCode(writer) {
var test = this.test;
var consequent = this.consequent;
var alternate = this.alternate;
writer.write(test);
writer.write(' ? ');
writer.write(consequent);
writer.write(' : ');
writer.write(alternate);
}
isCompoundExpression() {
return true;
}
toJSON() {
return {
type: 'ConditionalExpression',
test: this.test,
consequent: this.consequent,
alternate: this.alternate
};
}
walk(walker) {
this.test = walker.walk(this.test);
this.consequent = walker.walk(this.consequent);
this.alternate = walker.walk(this.alternate);
}
toString() {
var test = this.test;
var consequent = this.consequent;
var alternate = this.alternate;
return test.toString() + ' ? ' + consequent + ' : ' + alternate;
}
}
module.exports = ConditionalExpression;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 1 | 'use strict';
class Container {
constructor(node) {
this.node = node;
}
toJSON() {
return this.items;
}
}
module.exports = Container;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 1 1 | 'use strict';
var Node = require('./Node');
class ContainerNode extends Node {
constructor(type) {
super(type);
this.body = this.makeContainer([]);
}
generateCode(codegen) {
return codegen.generateCode(this.body);
}
walk(walker) {
this.body = walker.walk(this.body);
}
}
module.exports = ContainerNode;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var HtmlElement = require('./HtmlElement');
var removeDashes = require('../util/removeDashes');
var safeVarName = require('../util/safeVarName');
var ok = require('assert').ok;
var Node = require('./Node');
var CUSTOM_TAG_KEY = Symbol('CustomTag');
function getNestedVariables(elNode, tagDef, codegen) {
var variableNames = [];
if (tagDef.forEachVariable) {
tagDef.forEachVariable((nestedVar) => {
var varName;
if (nestedVar.nameFromAttribute) {
var possibleNameAttributes = nestedVar.nameFromAttribute.split(/\s+or\s+|\s*,\s*/i);
for (var i = 0, len = possibleNameAttributes.length; i < len; i++) {
var attrName = possibleNameAttributes[i];
var keep = false;
if (attrName.endsWith('|keep')) {
keep = true;
attrName = attrName.slice(0, 0 - '|keep'.length);
possibleNameAttributes[i] = attrName;
}
varName = elNode.getAttributeValue(attrName);
if (varName) {
if (varName.type !== 'Literal' || typeof varName.value !== 'string') {
codegen.addError('The value of the ' + attrName + ' is expected to be a string');
codegen.addError('Attribute ' + possibleNameAttributes.join(' or ') + ' is required');
varName = '_var'; // Let it continue with errors
}
varName = varName.value;
if (!keep) {
elNode.removeAttribute(attrName);
}
break;
}
}
if (!varName) {
codegen.addError('Attribute ' + possibleNameAttributes.join(' or ') + ' is required');
varName = '_var'; // Let it continue with errors
}
} else {
varName = nestedVar.name;
if (!varName) {
codegen.addError('Variable name is required');
varName = '_var'; // Let it continue with errors
}
}
variableNames.push(codegen.builder.identifier(varName));
});
}
if (elNode.additionalNestedVars.length) {
elNode.additionalNestedVars.forEach((varName) => {
variableNames.push(codegen.builder.identifier(varName));
});
}
return variableNames;
}
function getAllowedAttributesString(tagName, context) {
var attrNames = [];
var tagDef = context.taglibLookup.getTag(tagName);
if (tagDef) {
tagDef.forEachAttribute((attrDef) => {
attrNames.push(attrDef.name);
});
return attrNames.length ? attrNames.join(', ') : '(none)';
} else {
return null;
}
}
function checkIfNestedTagCanBeAddedDirectlyToInput(nestedTag, parentCustomTag) {
if (!nestedTag._isDirectlyNestedTag) {
return false;
}
var isRepeated = nestedTag.tagDef.isRepeated;
if (!isRepeated) {
return true;
}
let tagName = nestedTag.tagDef.name;
let previousMatchingNestedTags = parentCustomTag._foundNestedTagsByName[tagName];
if (!previousMatchingNestedTags) {
return true;
}
for (let i=0; i<previousMatchingNestedTags.length; i++) {
let previousNestedTag = previousMatchingNestedTags[i];
if (!previousNestedTag._isDirectlyNestedTag) {
return false;
}
}
return true;
}
function getNextNestedTagVarName(tagDef, context) {
var key = 'customTag' + tagDef.name;
var nestedTagVarInfo = context.data[key] || (context.data[key] = {
next: 0
});
return safeVarName(tagDef.name) + (nestedTagVarInfo.next++);
}
function getNextRenderBodyVar(context) {
var key = 'CustomTag_renderBodyVar';
var nextVarInfo = context.data[key] || (context.data[key] = {
next: 0
});
return 'renderBodyConditional'+ (nextVarInfo.next++);
}
function processDirectlyNestedTags(node, codegen) {
node.forEachChild((child) => {
if (child.type === 'CustomTag') {
let customTag = child;
var tagDef = customTag.resolveTagDef(codegen);
if (tagDef.isNestedTag) {
customTag._isDirectlyNestedTag = true;
}
} else if (child.type === 'If') {
if (child.nextSibling && child.nextSibling.type === 'Else') {
return;
}
let ifNode = child;
let childChild = child.childCount === 1 && child.firstChild;
if (childChild && childChild.type === 'CustomTag') {
let customTag = childChild;
let tagDef = customTag.resolveTagDef(codegen);
if (tagDef.isNestedTag && !tagDef.isRepeated) {
let condition = codegen.generateCode(ifNode.test);
customTag._isDirectlyNestedTag = true;
customTag._condition = condition;
ifNode.replaceWith(customTag);
}
}
}
});
}
function merge(props1, props2, context) {
if (!props2) {
return props1;
}
if (!(props2 instanceof Node)) {
if (Object.keys(props2).length === 0) {
return props1;
}
}
if (props1 instanceof Node) {
let mergeVar = context.helper('merge');
if (!(props2 instanceof Node)) {
props2 = context.builder.literal(props2);
}
return context.builder.functionCall(mergeVar, [
props2, // Input props from the attributes take precedence
props1
]);
} else {
if (props2 instanceof Node) {
let mergeVar = context.helper('merge');
return context.builder.functionCall(mergeVar, [
props2, // Input props from the attributes take precedence
props1
]);
} else {
if (props1._arg) {
let mergeVar = context.helper('merge');
props1._arg = context.builder.functionCall(mergeVar, [
context.builder.literal(props2), // Input props from the attributes take precedence
props1._arg
]);
return props1;
} else {
return Object.assign(props1, props2);
}
}
}
}
class CustomTag extends HtmlElement {
constructor(el, tagDef) {
super(el);
this.type = 'CustomTag';
this.tagDef = tagDef;
this.additionalNestedVars = [];
this._nestedTagVar = null;
this._inputProps = null;
this._isDirectlyNestedTag = false;
this._condition = null;
this._foundNestedTagsByName = {};
this._hasDynamicNestedTags = false;
this._additionalProps = null;
this._rendererPath = null;
this.dynamicAttributes = undefined;
}
buildInputProps(codegen) {
var inputProps = this._inputProps;
if (inputProps) {
return inputProps;
}
var context = codegen.context;
var tagDef = this.resolveTagDef(codegen);
inputProps = {};
function handleAttr(attrName, attrValue, attrDef) {
if (!attrDef) {
return; // Skip over attributes that are not supported
}
if (attrValue == null) {
attrValue = context.builder.literalTrue();
}
var propName;
var parentPropName;
if (attrDef.dynamicAttribute) {
// Dynamic attributes are allowed attributes
// that are not declared (i.e. "*" attributes)
//
if (attrDef.removeDashes === true || attrDef.preserveName === false) {
propName = removeDashes(attrName);
} else {
propName = attrName;
}
if (attrDef.targetProperty) {
parentPropName = attrDef.targetProperty;
}
} else {
// Attributes map to properties and we allow the taglib
// author to control how an attribute name resolves
// to a property name.
if (attrDef.targetProperty) {
propName = attrDef.targetProperty;
} else if (attrDef.preserveName === true) {
propName = attrName;
} else {
propName = removeDashes(attrName);
}
}
if (attrDef.type === 'path') {
attrValue = context.resolvePath(attrValue);
} else if (attrDef.type === 'template') {
attrValue = context.resolveTemplate(attrValue);
}
if (parentPropName) {
let parent = inputProps[parentPropName] || (inputProps[parentPropName] = {});
parent[propName] = attrValue;
} else {
inputProps[propName] = attrValue;
}
}
if (tagDef.forEachAttribute) {
// Add default values for any attributes from the tag definition. These added properties may get overridden
// by get overridden from the attributes found on the actual HTML element.
tagDef.forEachAttribute(function (attrDef) {
if (attrDef.hasOwnProperty('defaultValue')) {
handleAttr(
attrDef.name,
context.builder.literal(attrDef.defaultValue),
attrDef);
}
});
}
let tagName = tagDef.isNestedTag ? tagDef.name : this.tagName;
// Loop over the attributes found on the HTML element and add the corresponding properties
// to the input object for the custom tag
this.forEachAttribute((attr) => {
var attrName = attr.name;
if (!attrName) {
return; // Skip attributes with no names
}
var attrDef = attr.def || context.taglibLookup.getAttribute(tagName, attrName) || tagDef.getAttribute(attr.name);
if (!attrDef) {
var errorMessage = 'Unsupported attribute of "' + attrName + '" found on the <' + this.tagName + '> custom tag.';
let allowedAttributesString = getAllowedAttributesString(tagName, context);
if (allowedAttributesString) {
errorMessage += ' Allowed attributes: ' + allowedAttributesString;
}
context.addError(this, errorMessage);
return; // Skip over attributes that are not supported
}
handleAttr(attrName, attr.value, attrDef);
});
if (tagDef.forEachImportedVariable) {
// Imported variables are used to add input properties to a custom tag based on data/variables
// found in the compiled template
tagDef.forEachImportedVariable(function(importedVariable) {
let propName = importedVariable.targetProperty;
let propExpression = importedVariable.expression;
inputProps[propName] = propExpression;
});
}
this._inputProps = inputProps;
return inputProps;
}
resolveTagDef(codegen) {
var context = codegen.context;
var tagDef = this.tagDef;
if (!tagDef) {
if (this.tagName && this.tagName.startsWith('@')) {
var parentCustomTag = context.getData(CUSTOM_TAG_KEY);
if (!parentCustomTag) {
codegen.addError('Invalid usage of the <' + this.tagName + '> nested tag. Tag not nested within a custom tag.');
return null;
}
var parentTagDef = parentCustomTag.tagDef;
if (!parentTagDef) {
throw new Error('"tagDef" is expected for CustomTag: ' + parentCustomTag.tagName);
}
var nestedTagName = this.tagName.substring(1);
var fullyQualifiedName = parentCustomTag.tagDef.name + ':' + nestedTagName;
tagDef = this.tagDef = context.getTagDef(fullyQualifiedName);
if (!tagDef) {
// This nested tag is not declared, but we will allow it to go through
var taglibLoader = require('../taglib-loader');
tagDef = this.tagDef = taglibLoader.loadTag({
name: fullyQualifiedName,
attributes: {
'*': {
targetProperty: null
}
}
}, context.filename);
tagDef.isNestedTag = true;
tagDef.isRepeated = false;
tagDef.targetProperty = nestedTagName;
}
} else {
throw new Error('"tagDef" is required for CustomTag');
}
this.tagDef = tagDef;
}
return tagDef;
}
addNestedVariable(name) {
ok(name, '"name" is required');
this.additionalNestedVars.push(name);
}
addNestedTag(nestedTag) {
var tagName = nestedTag.tagDef.name;
var byNameArray = this._foundNestedTagsByName[tagName] ||
(this._foundNestedTagsByName[tagName] = []);
byNameArray.push(nestedTag);
}
addProps(additionalProps) {
if (!this._additionalProps) {
this._additionalProps = {};
}
Object.assign(this._additionalProps, additionalProps);
}
hasProp(name) {
return this._additionalProps && this._additionalProps.hasOwnProperty(name);
}
addProp(name, value) {
if (!this._additionalProps) {
this._additionalProps = {};
}
this._additionalProps[name] = value;
}
setRendererPath(path) {
ok(typeof path === 'string', '"path" should be a string');
this._rendererPath = path;
}
getNestedTagVar(context) {
if (!this._nestedTagVar) {
var tagDef = this.tagDef;
var builder = context.builder;
var nextNestedTagVarName = getNextNestedTagVarName(tagDef, context);
this._nestedTagVar = builder.identifier(nextNestedTagVarName);
}
return this._nestedTagVar;
}
generateRenderTagCode(codegen, tagVar, tagArgs) {
return codegen.builder.functionCall(tagVar, tagArgs);
}
generateCode(codegen) {
if (this.type !== 'CustomTag') {
throw new Error(this.type);
}
var builder = codegen.builder;
var context = codegen.context;
var tagDef = this.resolveTagDef(codegen);
if (!tagDef) {
// The tag def was not able to be resolved and an error should have already
// been added to the context
return null;
}
var parentCustomTag;
context.pushData(CUSTOM_TAG_KEY, this);
processDirectlyNestedTags(this, codegen);
var body = codegen.generateCode(this.body);
context.popData(CUSTOM_TAG_KEY);
var isNestedTag = tagDef.isNestedTag === true;
if (isNestedTag) {
parentCustomTag = context.getData(CUSTOM_TAG_KEY);
if (!parentCustomTag) {
if (tagDef.parentTagName) {
codegen.addError(`Invalid usage of the <${this.tagName}> nested tag. Tag not nested within a <${tagDef.parentTagName}> tag.`);
} else {
codegen.addError(`Invalid usage of the <${this.tagName}> nested tag. Tag not nested within a custom tag.`);
}
return null;
}
parentCustomTag.addNestedTag(this);
if (checkIfNestedTagCanBeAddedDirectlyToInput(this, parentCustomTag)) {
let inputProps = this.buildInputProps(codegen);
if (body && body.length) {
inputProps.renderBody = codegen.builder.renderBodyFunction(body);
}
if (tagDef.isRepeated) {
var currentValue = parentCustomTag.getAttributeValue(tagDef.targetProperty);
if (currentValue) {
currentValue.value.push(inputProps);
} else {
parentCustomTag.setAttributeValue(tagDef.targetProperty, builder.literal([
inputProps
]));
}
} else {
let nestedTagValue = builder.literal(inputProps);
if (this._condition) {
nestedTagValue = builder.binaryExpression(this._condition, '&&', nestedTagValue);
}
parentCustomTag.setAttributeValue(tagDef.targetProperty, nestedTagValue);
}
return null;
} else {
this._isDirectlyNestedTag = false;
parentCustomTag._hasDynamicNestedTags = true;
}
}
var hasDynamicNestedTags = this._hasDynamicNestedTags;
var bodyOnlyIf = this.bodyOnlyIf;
// let parentTagVar;
var nestedVariableNames = getNestedVariables(this, tagDef, codegen);
var inputProps = this.buildInputProps(codegen);
var renderBodyFunction;
if (body && body.length) {
if (tagDef.bodyFunction) {
let bodyFunction = tagDef.bodyFunction;
let bodyFunctionName = bodyFunction.name;
let bodyFunctionParams = bodyFunction.params.map(function(param) {
return builder.identifier(param);
});
inputProps[bodyFunctionName] = builder.functionDeclaration(bodyFunctionName, bodyFunctionParams, body);
} else {
renderBodyFunction = context.builder.renderBodyFunction(body);
if (hasDynamicNestedTags) {
renderBodyFunction.params.push(this._nestedTagVar);
} else {
if (nestedVariableNames && nestedVariableNames.length) {
renderBodyFunction.params = renderBodyFunction.params.concat(nestedVariableNames);
}
}
}
}
var renderBodyFunctionVarIdentifier;
var renderBodyFunctionVar;
// Store the renderBody function with the input, but only if the body does not have
// nested tags
if (renderBodyFunction) {
if (bodyOnlyIf) {
// Move the renderBody function into a local variable
renderBodyFunctionVarIdentifier = builder.identifier(getNextRenderBodyVar(context));
renderBodyFunctionVar = builder.var(renderBodyFunctionVarIdentifier, renderBodyFunction);
inputProps.renderBody = renderBodyFunctionVarIdentifier;
} else {
inputProps.renderBody = renderBodyFunction;
}
} else {
bodyOnlyIf = null;
}
var argExpression;
if (this.argument) {
argExpression = builder.parseExpression(this.argument);
}
var additionalProps = this._additionalProps;
if (additionalProps) {
inputProps = merge(additionalProps, inputProps, context);
}
if (argExpression) {
inputProps = merge(argExpression, inputProps, context);
}
if (this.dynamicAttributes) {
this.dynamicAttributes.forEach((dynamicAttributesExpression) => {
inputProps = merge(dynamicAttributesExpression, inputProps, context);
});
}
if (!(inputProps instanceof Node)) {
inputProps = builder.literal(inputProps);
}
if (hasDynamicNestedTags) {
inputProps = builder.functionCall(context.helper('mergeNestedTagsHelper'), [ inputProps ]);
}
var rendererPath = this._rendererPath || tagDef.renderer;
var rendererRequirePath;
var requireRendererFunctionCall;
if (rendererPath) {
rendererRequirePath = context.getRequirePath(rendererPath);
requireRendererFunctionCall = builder.require(JSON.stringify(rendererRequirePath));
} else {
requireRendererFunctionCall = builder.literal(null);
}
var finalNode;
var tagVarName = tagDef.name + (tagDef.isNestedTag ? '_nested_tag' : '_tag');
if (tagDef.template) {
var templateRequirePath = context.getRequirePath(tagDef.template);
var templateVar = context.importTemplate(templateRequirePath, tagDef.name + '_template');
let loadTag = builder.functionCall(context.helper('loadTag'), [templateVar]);
let tagVar = codegen.addStaticVar(tagVarName, loadTag);
finalNode = this.generateRenderTagCode(codegen, tagVar, [ inputProps, builder.identifierOut() ]);
} else {
if (rendererRequirePath) {
codegen.pushMeta('tags', builder.literal(rendererRequirePath), true);
}
let loadTag;
let tagArgs;
if (isNestedTag) {
let loadTagArgs = [ builder.literal(tagDef.targetProperty) ];
if (tagDef.isRepeated) {
loadTagArgs.push(builder.literal(1)); // isRepeated
}
loadTag = builder.functionCall(context.helper('loadNestedTag'), loadTagArgs);
tagArgs = [inputProps, parentCustomTag.getNestedTagVar(context) ];
} else {
loadTag = builder.functionCall(context.helper('loadTag'), [
requireRendererFunctionCall // The first param is the renderer
]);
tagArgs = [inputProps, builder.identifierOut() ];
}
let tagVar = codegen.addStaticVar(tagVarName, loadTag);
if (isNestedTag) {
finalNode = builder.functionCall(tagVar, tagArgs);
} else {
finalNode = this.generateRenderTagCode(codegen, tagVar, tagArgs);
}
}
if (bodyOnlyIf && renderBodyFunctionVar) {
var ifStatement = builder.ifStatement(
bodyOnlyIf,
[
builder.functionCall(renderBodyFunctionVarIdentifier, [builder.identifierOut()])
],
builder.elseStatement([
finalNode
]));
return [
renderBodyFunctionVar,
ifStatement
];
} else {
return finalNode;
}
}
addDynamicAttributes(expression) {
if (!this.dynamicAttributes) {
this.dynamicAttributes = [];
}
this.dynamicAttributes.push(expression);
}
}
module.exports = CustomTag;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 1 1 | 'use strict';
var Node = require('./Node');
class Declaration extends Node {
constructor(def) {
super('Declaration');
this.declaration = def.declaration;
}
generateHTMLCode(codegen) {
var builder = codegen.builder;
return [
builder.htmlLiteral('<?'),
codegen.generateCode(builder.text(this.declaration)),
builder.htmlLiteral('?>')
];
}
toJSON() {
return {
type: this.type,
value: this.value
};
}
}
module.exports = Declaration;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 1 1 | 'use strict';
var Node = require('./Node');
class DocumentType extends Node {
constructor(def) {
super('DocumentType');
this.documentType = def.documentType;
}
generateHTMLCode(codegen) {
var builder = codegen.builder;
return [
builder.htmlLiteral('<!'),
builder.html(codegen.generateCode(this.documentType)),
builder.htmlLiteral('>')
];
}
generateVDOMCode(codegen) {
return null;
}
toJSON() {
return {
type: this.type,
value: this.value
};
}
}
module.exports = DocumentType;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 1 1 | 'use strict';
var Node = require('./Node');
class Else extends Node {
constructor(def) {
super('Else');
this.body = this.makeContainer(def.body);
this.matched = false;
}
generateCode(codegen) {
if (!this.matched) {
codegen.addError('Unmatched else statement');
return;
}
this.body = codegen.generateCode(this.body);
return this;
}
writeCode(writer) {
var body = this.body;
writer.writeBlock(body);
writer.write('\n');
}
walk(walker) {
this.body = walker.walk(this.body);
}
}
module.exports = Else;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 1 1 | 'use strict';
var Node = require('./Node');
class ElseIf extends Node {
constructor(def) {
super('ElseIf');
this.test = def.test;
this.body = this.makeContainer(def.body);
this.else = def.else;
this.matched = false;
}
generateCode(codegen) {
if (!this.matched) {
codegen.addError('Unmatched else statement');
return;
}
return codegen.builder.ifStatement(this.test, this.body, this.else);
}
walk(walker) {
this.test = walker.walk(this.test);
this.body = walker.walk(this.body);
this.else = walker.walk(this.else);
}
}
module.exports = ElseIf;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 1 1 1 | 'use strict';
var Node = require('./Node');
var ok = require('assert').ok;
class Expression extends Node {
constructor(def) {
super('Expression');
this.value = def.value;
ok(this.value != null, 'Invalid expression');
}
generateCode(codegen) {
return this;
}
writeCode(writer) {
writer.write(this.value);
}
isCompoundExpression() {
return true;
}
toString() {
return this.value;
}
}
module.exports = Expression;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | 1 1 1 | 'use strict';
var ok = require('assert').ok;
var Node = require('./Node');
class ForEach extends Node {
constructor(def) {
super('ForEach');
this.varName = def.varName;
this.in = def.in;
this.body = this.makeContainer(def.body);
this.separator = def.separator;
this.statusVarName = def.statusVarName;
this.iterator = def.iterator;
this.isArray = def.isArray;
ok(this.varName, '"varName" is required');
ok(this.in != null, '"in" is required');
}
generateCode(codegen) {
var varName = this.varName;
var inExpression = this.in;
var separator = this.separator;
var statusVarName = this.statusVarName;
var iterator = this.iterator;
var context = codegen.context;
var builder = codegen.builder;
var isArray = this.isArray;
if (separator && !statusVarName) {
statusVarName = '__loop';
}
if (iterator) {
let params = [varName];
if (statusVarName) {
params.push(statusVarName);
}
return builder.functionCall(iterator, [
inExpression,
builder.functionDeclaration(null, params, this.body)
]);
} else if (statusVarName) {
let body = this.body;
if (separator) {
let isNotLastTest = builder.functionCall(
builder.memberExpression(statusVarName, builder.identifier('isLast')),
[]);
isNotLastTest = builder.negate(isNotLastTest);
body = body.items.concat([
builder.ifStatement(isNotLastTest, [
builder.text(separator, false)
])
]);
}
return builder.functionCall(context.helper('forEachWithStatusVar'), [
inExpression,
builder.functionDeclaration(null, [varName, statusVarName], body)
]);
} else {
if (isArray) {
context.addVar(varName.name);
var indexVarId = context.addVar(varName.name + '__i');
var arrayVarId = context.addVar(varName.name + '__array');
var lengthVarId = context.addVar(varName.name + '__len');
var init = builder.sequenceExpression([
builder.assignment(indexVarId, builder.literal(0)),
builder.assignment(arrayVarId, inExpression),
builder.assignment(lengthVarId, builder.binaryExpression(arrayVarId, '&&', builder.memberExpression(arrayVarId, builder.identifier('length'))))
]);
var test = builder.binaryExpression(indexVarId, '<', lengthVarId);
var update = builder.unaryExpression(indexVarId, '++');
var loopBody = [
builder.assignment(varName, builder.memberExpression(arrayVarId, indexVarId, true))
].concat(this.body);
return builder.forStatement(init, test, update, loopBody);
} else {
return builder.functionCall(context.helper('forEach'), [
inExpression,
builder.functionDeclaration(null, [varName], this.body)
]);
}
}
}
walk(walker) {
this.varName = walker.walk(this.varName);
this.in = walker.walk(this.in);
this.body = walker.walk(this.body);
this.separator = walker.walk(this.separator);
this.statusVarName = walker.walk(this.statusVarName);
this.iterator = walker.walk(this.iterator);
}
}
module.exports = ForEach;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | 1 1 1 | 'use strict';
var ok = require('assert').ok;
var Node = require('./Node');
class ForEachProp extends Node {
constructor(def) {
super('ForEachProp');
this.nameVarName = def.nameVarName;
this.valueVarName = def.valueVarName;
this.in = def.in;
this.separator = def.separator;
this.statusVarName = def.statusVarName;
this.body = this.makeContainer(def.body);
ok(this.nameVarName, '"nameVarName" is required');
ok(this.valueVarName != null, '"valueVarName" is required');
ok(this.in != null, '"in" is required');
}
generateCode(codegen) {
var context = codegen.context;
var nameVarName = this.nameVarName;
var valueVarName = this.valueVarName;
var inExpression = this.in;
var body = this.body;
var separator = this.separator;
var statusVarName = this.statusVarName;
if (separator && !statusVarName) {
statusVarName = '__loop';
}
var builder = codegen.builder;
if (statusVarName) {
let helperVar = context.helper('forEachPropStatusVar');
let forEachVarName = codegen.addStaticVar('forEacPropStatusVar', helperVar);
let body = this.body;
if (separator) {
let isNotLastTest = builder.functionCall(
builder.memberExpression(statusVarName, builder.identifier('isLast')),
[]);
isNotLastTest = builder.negate(isNotLastTest);
body = body.items.concat([
builder.ifStatement(isNotLastTest, [
builder.text(separator)
])
]);
}
return builder.functionCall(forEachVarName, [
inExpression,
builder.functionDeclaration(null, [nameVarName, valueVarName, statusVarName], body)
]);
} else {
return builder.functionCall(
context.helper('forEachProp'),
[
inExpression,
builder.functionDeclaration(null, [nameVarName, valueVarName], body)
]);
}
}
walk(walker) {
this.nameVarName = walker.walk(this.nameVarName);
this.valueVarName = walker.walk(this.valueVarName);
this.in = walker.walk(this.in);
this.body = walker.walk(this.body);
}
}
module.exports = ForEachProp;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 1 1 1 1 1 | 'use strict';
var ok = require('assert').ok;
var Node = require('./Node');
var Literal = require('./Literal');
var Identifier = require('./Identifier');
class ForRange extends Node {
constructor(def) {
super('ForRange');
this.varName = def.varName;
this.body = this.makeContainer(def.body);
this.from = def.from;
this.to = def.to;
this.step = def.step;
ok(this.varName, '"varName" is required');
ok(this.from != null, '"from" is required');
}
generateCode(codegen) {
var context = codegen.context;
var varName = this.varName;
var from = this.from;
var to = this.to;
var step = this.step;
var builder = codegen.builder;
if (varName instanceof Identifier) {
varName = varName.name;
}
if (step == null) {
let fromLiteral = (from instanceof Literal) && from.value;
let toLiteral = (to instanceof Literal) && to.value;
if (typeof fromLiteral === 'number' && typeof toLiteral === 'number') {
if (fromLiteral > toLiteral) {
step = builder.literal(-1);
} else {
step = builder.literal(1);
}
}
}
if (step == null) {
step = builder.literalNull();
}
return builder.functionCall(context.helper('forRange'), [
from,
to,
step,
builder.functionDeclaration(null, [varName], this.body)
]);
}
walk(walker) {
this.varName = walker.walk(this.varName);
this.body = walker.walk(this.body);
this.from = walker.walk(this.from);
this.to = walker.walk(this.to);
this.step = walker.walk(this.step);
}
}
module.exports = ForRange;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | 1 1 | 'use strict';
var Node = require('./Node');
class ForStatement extends Node {
constructor(def) {
super('ForStatement');
this.init = def.init;
this.test = def.test;
this.update = def.update;
this.body = this.makeContainer(def.body);
}
generateCode(codegen) {
this.init = codegen.generateCode(this.init);
this.test = codegen.generateCode(this.test);
this.update = codegen.generateCode(this.update);
this.body = codegen.generateCode(this.body);
return this;
}
writeCode(writer) {
var init = this.init;
var test = this.test;
var update = this.update;
var body = this.body;
writer.write('for (');
if (init) {
writer.write(init);
}
writer.write('; ');
if (test) {
writer.write(test);
}
writer.write('; ');
if (update) {
writer.write(update);
}
writer.write(') ');
writer.writeBlock(body);
writer.write('\n');
}
walk(walker) {
this.init = walker.walk(this.init);
this.test = walker.walk(this.test);
this.update = walker.walk(this.update);
this.body = walker.walk(this.body);
}
}
module.exports = ForStatement;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | 1 1 1 1 | 'use strict';
var ok = require('assert').ok;
var Node = require('./Node');
var isCompoundExpression = require('../util/isCompoundExpression');
class FunctionCall extends Node {
constructor(def) {
super('FunctionCall');
this.callee = def.callee;
ok(this.callee, '"callee" is required');
let args = this.args = def.args;
if (args) {
if (!Array.isArray(args)) {
throw new Error('Invalid args');
}
for (let i=0; i<args.length; i++) {
let arg = args[i];
if (!arg) {
throw new Error('Arg ' + i + ' is not valid for function call: ' + JSON.stringify(this.toJSON(), null, 2));
}
}
}
}
generateCode(codegen) {
this.callee = codegen.generateCode(this.callee);
this.args = codegen.generateCode(this.args);
return this;
}
writeCode(writer) {
var callee = this.callee;
var args = this.args;
var wrapWithParens = isCompoundExpression(callee);
if (wrapWithParens) {
writer.write('(');
}
writer.write(callee);
if (wrapWithParens) {
writer.write(')');
}
writer.write('(');
if (args && args.length) {
for (let i=0, argsLen = args.length; i<argsLen; i++) {
if (i !== 0) {
writer.write(', ');
}
let arg = args[i];
if (!arg) {
throw new Error('Arg ' + i + ' is not valid for function call: ' + JSON.stringify(this.toJSON()));
}
writer.write(arg);
}
}
writer.write(')');
}
walk(walker) {
this.callee = walker.walk(this.callee);
this.args = walker.walk(this.args);
}
toString() {
var callee = this.callee;
var args = this.args;
var result = callee.toString() + '(';
if (args && args.length) {
for (let i=0, argsLen = args.length; i<argsLen; i++) {
if (i !== 0) {
result += ', ';
}
let arg = args[i];
if (!arg) {
throw new Error('Arg ' + i + ' is not valid for function call: ' + JSON.stringify(this.toJSON()));
}
result += arg;
}
}
result += ')';
return result;
}
}
module.exports = FunctionCall;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | 1 1 1 | 'use strict';
var Node = require('./Node');
var ok = require('assert').ok;
class FunctionDeclaration extends Node {
constructor(def) {
super('FunctionDeclaration');
this.name = def.name;
this.params = def.params;
this.body = this.makeContainer(def.body);
}
generateCode(codegen) {
var oldInFunction = codegen.inFunction;
codegen.inFunction = true;
this.body = codegen.generateCode(this.body);
codegen.inFunction = oldInFunction;
return this;
}
writeCode(writer) {
var name = this.name;
var params = this.params;
var body = this.body;
var statement = this.statement;
if (name != null) {
ok(typeof name === 'string' || name.type === 'Identifier', 'Function name should be a string or Identifier');
}
if (name) {
writer.write('function ');
writer.write(name);
writer.write('(');
} else {
writer.write('function(');
}
if (params && params.length) {
for (let i=0, paramsLen = params.length; i<paramsLen; i++) {
if (i !== 0) {
writer.write(', ');
}
var param = params[i];
if (typeof param === 'string') {
writer.write(param);
} else {
if (param.type !== 'Identifier') {
throw new Error('Illegal param ' + JSON.stringify(param) + ' for FunctionDeclaration: ' + JSON.stringify(this));
}
writer.write(param);
}
}
}
writer.write(') ');
writer.writeBlock(body);
if (statement) {
writer.write('\n');
}
}
isCompoundExpression() {
return true;
}
walk(walker) {
this.name = walker.walk(this.name);
this.params = walker.walk(this.params);
this.body = walker.walk(this.body);
}
}
module.exports = FunctionDeclaration;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | 1 1 1 1 | 'use strict';
var Node = require('./Node');
var Literal = require('./Literal');
var isCompoundExpression = require('../util/isCompoundExpression');
class Html extends Node {
constructor(def) {
super('Html');
this.argument = def.argument;
}
_append(appendArgument) {
var argument = this.argument;
if (Array.isArray(argument)) {
var len = argument.length;
var last = argument[len-1];
if (last instanceof Literal && appendArgument instanceof Literal) {
last.value += appendArgument.value;
} else {
this.argument.push(appendArgument);
}
} else {
if (argument instanceof Literal && appendArgument instanceof Literal) {
argument.value += appendArgument.value;
} else {
this.argument = [ this.argument, appendArgument ];
}
}
}
append(html) {
var appendArgument = html.argument;
if (!appendArgument) {
return;
}
if (Array.isArray(appendArgument)) {
appendArgument.forEach(this._append, this);
} else {
this._append(appendArgument);
}
}
generateHTMLCode() {
return this;
}
writeCode(writer) {
var argument = this.argument;
if (Array.isArray(argument)) {
let args = argument;
for (let i=0, len=args.length; i<len; i++) {
let arg = args[i];
if (i === 0) {
writer.write('out.w(');
} else {
writer.write(' +\n');
writer.writeLineIndent();
writer.writeIndent();
}
if (isCompoundExpression(arg)) {
writer.write(['(', arg, ')']);
} else {
writer.write(arg);
}
}
writer.write(')');
} else {
writer.write('out.w(');
writer.write(argument);
writer.write(')');
}
}
walk(walker) {
this.argument = walker.walk(this.argument);
}
}
module.exports = Html;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | 1 1 1 1 | 'use strict';
var ok = require('assert').ok;
var HtmlAttribute = require('./HtmlAttribute');
var Node = require('./Node');
class HtmlAttributeCollection {
constructor(attributes) {
this.replaceAttributes(attributes);
}
addAttribute(newAttr) {
if (arguments.length === 2) {
let name = arguments[0];
let expression = arguments[1];
newAttr = new HtmlAttribute(name, expression);
} else if (!HtmlAttribute.isHtmlAttribute(newAttr)) {
newAttr = new HtmlAttribute(newAttr);
}
var name = newAttr.name;
if (this.lookup.hasOwnProperty(name)) {
for (var i=0; i<this.all.length; i++) {
var curAttr = this.all[i];
if (curAttr.name === name) {
this.all.splice(i, 1);
break;
}
}
}
if (name) {
this.lookup[name] = newAttr;
}
this.all.push(newAttr);
}
removeAttribute(name) {
ok(typeof name === 'string', 'Invalid attribute name');
if (!this.lookup.hasOwnProperty(name)) {
return false;
}
delete this.lookup[name];
for (var i=0; i<this.all.length; i++) {
var curAttr = this.all[i];
if (curAttr.name === name) {
this.all.splice(i, 1);
break;
}
}
return true;
}
renameAttribute(oldName, newName) {
var key = oldName;
var attr = this.lookup[key];
if (!attr) {
return;
}
attr.name = newName;
delete this.lookup[key];
this.lookup[key] = attr;
}
removeAllAttributes() {
this.replaceAttributes([]);
}
hasAttribute(name) {
ok(typeof name === 'string', 'Invalid attribute name');
return this.lookup.hasOwnProperty(name);
}
hasAttributes() {
return this.all.length > 0;
}
getAttribute(name) {
return this.lookup[name];
}
setAttributeValue(name, value, escape) {
var attr = this.getAttribute(name);
if (attr) {
attr.value = value;
if (typeof escape === 'boolean') {
attr.escape = escape;
}
} else {
this.addAttribute({
name: name,
value: value,
escape: escape
});
}
}
getAttributes() {
return this.all;
}
toJSON() {
return this.all;
}
toString() {
return JSON.stringify(this.all);
}
replaceAttributes(attributes) {
this.all = [];
this.lookup = {};
if (attributes) {
if (Array.isArray(attributes)) {
attributes.forEach((attr) => {
this.addAttribute(attr);
});
} else {
for (var attrName in attributes) {
if (attributes.hasOwnProperty(attrName)) {
let attrValue = attributes[attrName];
let attrDef;
if (attrValue != null && typeof attrValue === 'object' && !(attrValue instanceof Node)) {
attrDef = attrValue;
attrDef.name = attrName;
} else {
attrDef = {
name: attrName,
value: attrValue
};
}
this.addAttribute(attrDef);
}
}
}
}
}
walk(walker) {
var newAttributes = walker.walk(this.all);
this.replaceAttributes(newAttributes);
}
}
module.exports = HtmlAttributeCollection;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 1 1 | 'use strict';
var Node = require('./Node');
class HtmlComment extends Node {
constructor(def) {
super('HtmlComment');
this.comment = def.comment;
}
generateHTMLCode(codegen) {
var comment = this.comment;
var builder = codegen.builder;
return [
builder.htmlLiteral('<!--'),
builder.html(comment),
builder.htmlLiteral('-->')
];
}
generateVDOMCode(codegen) {
var comment = this.comment;
var builder = codegen.builder;
return builder.functionCall(
builder.memberExpression(
builder.identifierOut(),
builder.identifier('comment')),
[
comment
]);
}
walk(walker) {
this.comment = walker.walk(this.comment);
}
}
module.exports = HtmlComment;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 1 2 2 1 | 'use strict';
var Node = require('./Node');
class Identifier extends Node {
constructor(def) {
super('Identifier');
this.name = def ? def.name : undefined;
}
generateCode(codegen) {
return this;
}
writeCode(writer) {
var name = this.name;
writer.write(name);
}
toString() {
return this.name;
}
}
module.exports = Identifier;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | 1 1 1 | 'use strict';
var Node = require('./Node');
function removeWhitespaceNodes(whitespaceNodes) {
for (var i=0; i<whitespaceNodes.length; i++) {
whitespaceNodes[i].detach();
}
whitespaceNodes.length = 0;
}
class If extends Node {
constructor(def) {
super('If');
this.test = def.test;
this.body = this.makeContainer(def.body);
this.else = def.else;
}
generateCode(codegen) {
if (this.else) {
this.else.matched = true;
} else {
// We want to match up any else/else if statements
// with this node so that we can generate the code
// correctly.
let previous = this;
let whitespaceNodes = [];
this.forEachNextSibling((curNode) => {
if (curNode.type === 'Else') {
curNode.detach();
if (whitespaceNodes.length) {
removeWhitespaceNodes(whitespaceNodes);
}
previous.else = curNode;
curNode.matched = true;
return false; // Stop searching
} else if (curNode.type === 'ElseIf') {
curNode.detach();
if (whitespaceNodes.length) {
removeWhitespaceNodes(whitespaceNodes);
}
previous.else = curNode;
previous = curNode;
curNode.matched = true;
return true; // Keep searching since they may be more ElseIf/Else nodes...
} else if (curNode.type === 'Text') {
if (curNode.isWhitespace()) {
whitespaceNodes.push(curNode);
return true; // Just whitespace... keep searching
} else {
return false; // Stop searching
}
} else {
return false; // Stop searching
}
});
}
this.test = codegen.generateCode(this.test);
this.body = codegen.generateCode(this.body);
this.else = codegen.generateCode(this.else);
return this;
}
writeCode(writer) {
var test = this.test;
var body = this.body;
writer.write('if (');
writer.write(test);
writer.write(') ');
writer.writeBlock(body);
if (this.else) {
writer.write(' else ');
writer.write(this.else);
} else {
writer.write('\n');
}
}
appendChild(newChild) {
this.body.appendChild(newChild);
}
walk(walker) {
this.test = walker.walk(this.test);
this.body = walker.walk(this.body);
this.else = walker.walk(this.else);
}
}
module.exports = If;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | 1 1 1 1 | 'use strict';
var Node = require('./Node');
var ok = require('assert').ok;
function removeTrailingUndefineds(args) {
var i;
var last = args.length-1;
for (i=last; i>=0; i--) {
if (args[i].type !== 'Literal' || args[i].value !== undefined) {
break;
}
}
if (i !== last) {
args = args.slice(0, i+1);
}
return args;
}
class InvokeMacro extends Node {
constructor(def) {
super('InvokeMacro');
this.el = def.el;
this.name = def.name;
this.args = def.args;
this.body = this.makeContainer(def.body);
if (this.name != null) {
ok(typeof this.name === 'string', 'Invalid macro name: ' + this.name);
}
}
generateCode(codegen) {
var el = this.el;
var name = this.name;
var args = this.args;
var body = this.body;
var builder = codegen.builder;
var macroDef;
if (el) {
name = el.tagName;
body = el.body;
if (typeof name !== 'string') {
codegen.context.addError(el, 'Element node with a dynamic tag name cannot be used to invoke a macro', 'ERR_INVOKE_MACRO');
return;
}
macroDef = codegen.context.getRegisteredMacro(name);
if (!macroDef) {
codegen.context.addError(el, 'Element node does not correspond to a macro', 'ERR_INVOKE_MACRO');
return;
}
if (el.argument) {
args = builder.parseJavaScriptArgs(el.argument);
} else {
args = new Array(macroDef.params.length);
for (let i=0; i<args.length; i++) {
args[i] = builder.literal(undefined);
}
el.forEachAttribute((attr) => {
var paramName = attr.name;
var paramIndex = macroDef.getParamIndex(paramName);
if (paramIndex == null) {
codegen.context.addError(el, 'The "' + name + '" macro does not have a parameter named "' + paramName + '"', 'ERR_INVOKE_MACRO');
return;
}
var value = attr.value;
if (value == null) {
value = builder.literal(true);
}
args[paramIndex] = value;
});
}
} else {
macroDef = codegen.context.getRegisteredMacro(name);
if (!macroDef) {
codegen.addError('Macro not found with name "' + name + '"', 'ERR_INVOKE_MACRO');
return;
}
}
if (!args) {
args = [];
}
while (args.length < macroDef.params.length) {
args.push(builder.literal(undefined));
}
if (body && body.length) {
args[macroDef.getParamIndex('renderBody')] = builder.renderBodyFunction(body);
}
args[macroDef.getParamIndex('out')] = builder.identifier('out');
args = removeTrailingUndefineds(args);
return builder.functionCall(builder.identifier(macroDef.functionName), args);
}
walk(walker) {
this.el = walker.walk(this.el);
this.name = walker.walk(this.name);
this.args = walker.walk(this.args);
this.body = walker.walk(this.body);
}
}
module.exports = InvokeMacro;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | 1 1 1 1 4 4 1 | 'use strict';
var Node = require('./Node');
var isArray = Array.isArray;
const isValidJavaScriptVarName = require('../util/isValidJavaScriptVarName');
function walkValue(value, walker) {
if (!value) {
return value;
} else if (value instanceof Node) {
return walker.walk(value);
} else if (isArray(value)) {
let array = value;
for (let i=0; i<array.length; i++) {
let el = array[i];
array[i] = walkValue(el, walker);
}
return array;
} else if (typeof value === 'object') {
let object = value;
let keys = Object.keys(object);
for (let i=0; i<keys.length; i++) {
let key = keys[i];
let oldValue = object[key];
let newValue = walkValue(oldValue, walker);
if (newValue !== oldValue) {
object[key] = newValue;
}
}
return object;
} else {
return value;
}
}
class Literal extends Node {
constructor(def) {
super('Literal');
this.value = def.value;
}
generateCode(codegen) {
if (this.value != null) {
if (isArray(this.value)) {
for (var i=0; i<this.value.length; i++) {
this.value[i] = codegen.generateCode(this.value[i]);
}
} else if (typeof this.value === 'object') {
if (!(this.value instanceof RegExp)) {
var newObject = {};
for (var k in this.value) {
if (this.value.hasOwnProperty(k)) {
newObject[k] = codegen.generateCode(this.value[k]);
}
}
this.value = newObject;
}
}
}
return this;
}
writeCode(writer) {
var value = this.value;
writer.writeLiteral(value);
}
toString() {
var value = this.value;
if (value === null) {
return 'null';
} else if (value === undefined) {
return 'undefined';
} else if (typeof value === 'string') {
return JSON.stringify(value);
} else if (value === true) {
return 'true';
} else if (value === false) {
return 'false';
} else if (isArray(value)) {
return '[' + value.join(', ') + ']';
} else if (typeof value === 'number') {
return value.toString();
} else if (value instanceof RegExp) {
return value.toString();
} else if (typeof value === 'object') {
let keys = Object.keys(value);
if (keys.length === 0) {
return '{}';
}
var result = '{ ';
for (let i=0; i<keys.length; i++) {
let k = keys[i];
let v = value[k];
if (i !== 0) {
result += ', ';
}
if (isValidJavaScriptVarName(k)) {
result += k + ': ';
} else {
result += JSON.stringify(k) + ': ';
}
result += v;
}
return result + ' }';
}
}
walk(walker) {
walkValue(this.value, walker);
}
}
module.exports = Literal;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | 1 1 1 1 1 | 'use strict';
var Node = require('./Node');
var isCompoundExpression = require('../util/isCompoundExpression');
function generateCodeForOperand(node, writer) {
var wrap = isCompoundExpression(node);
if (wrap) {
writer.write('(');
}
writer.write(node);
if (wrap) {
writer.write(')');
}
}
function operandToString(node) {
var wrap = isCompoundExpression(node);
var result = '';
if (wrap) {
result += '(';
}
result += node;
if (wrap) {
result += ')';
}
return result;
}
class LogicalExpression extends Node {
constructor(def) {
super('LogicalExpression');
this.left = def.left;
this.operator = def.operator;
this.right = def.right;
}
generateCode(codegen) {
this.left = codegen.generateCode(this.left);
this.right = codegen.generateCode(this.right);
return this;
}
writeCode(writer) {
var left = this.left;
var operator = this.operator;
var right = this.right;
if (!left || !right) {
throw new Error('Invalid LogicalExpression: ' + this);
}
generateCodeForOperand(left, writer);
writer.write(' ');
writer.write(operator);
writer.write(' ');
generateCodeForOperand(right, writer);
}
isCompoundExpression() {
return true;
}
toJSON() {
return {
type: 'LogicalExpression',
left: this.left,
operator: this.operator,
right: this.right
};
}
walk(walker) {
this.left = walker.walk(this.left);
this.right = walker.walk(this.right);
}
toString() {
var left = this.left;
var operator = this.operator;
var right = this.right;
if (!left || !right) {
throw new Error('Invalid LogicalExpression: ' + this);
}
return operandToString(left) + ' ' + operator + ' ' + operandToString(right);
}
}
module.exports = LogicalExpression;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 1 1 1 | 'use strict';
var Node = require('./Node');
var ok = require('assert').ok;
class Macro extends Node {
constructor(def) {
super('Macro');
this.name = def.name;
this.params = def.params;
this.body = this.makeContainer(def.body);
if (this.params == null) {
this.params = [];
} else {
ok(Array.isArray(this.params), '"params" should be an array');
}
}
generateCode(codegen) {
var name = this.name;
var params = this.params || [];
var builder = codegen.builder;
var macroDef = codegen.context.registerMacro(name, params);
var functionName = macroDef.functionName;
// Walk the body after registering the macro
var body = codegen.generateCode(this.body);
return builder.functionDeclaration(functionName, macroDef.params, body);
}
walk(walker) {
this.body = walker.walk(this.body);
}
}
module.exports = Macro;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | 1 1 1 1 | 'use strict';
var Node = require('./Node');
var isCompoundExpression = require('../util/isCompoundExpression');
var ok = require('assert').ok;
class MemberExpression extends Node {
constructor(def) {
super('MemberExpression');
this.object = def.object;
this.property = def.property;
this.computed = def.computed;
ok(this.object, '"object" is required');
ok(this.property, '"property" is required');
}
generateCode(codegen) {
this.object = codegen.generateCode(this.object);
this.property = codegen.generateCode(this.property);
return this;
}
writeCode(writer) {
var object = this.object;
var property = this.property;
var computed = this.computed;
var wrapWithParens = isCompoundExpression(object);
if (wrapWithParens) {
writer.write('(');
}
writer.write(object);
if (wrapWithParens) {
writer.write(')');
}
if (computed) {
writer.write('[');
writer.write(property);
writer.write(']');
} else {
writer.write('.');
writer.write(property);
}
}
toJSON() {
return {
type: 'MemberExpression',
object: this.object,
property: this.property,
computed: this.computed
};
}
walk(walker) {
this.object = walker.walk(this.object);
this.property = walker.walk(this.property);
}
toString() {
var object = this.object;
var property = this.property;
var computed = this.computed;
var result = object.toString();
if (computed) {
result += '[' + property + ']';
} else {
result += '.' + property;
}
return result;
}
}
module.exports = MemberExpression;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | 1 1 1 | 'use strict';
var Node = require('./Node');
var isCompoundExpression = require('../util/isCompoundExpression');
class NewExpression extends Node {
constructor(def) {
super('NewExpression');
this.callee = def.callee;
this.args = def.args;
}
generateCode(codegen) {
this.callee = codegen.generateCode(this.callee);
this.args = codegen.generateCode(this.args);
return this;
}
writeCode(writer) {
var callee = this.callee;
var args = this.args;
writer.write('new ');
var wrap = isCompoundExpression(callee);
if (wrap) {
writer.write('(');
}
writer.write(callee);
if (wrap) {
writer.write(')');
}
writer.write('(');
if (args && args.length) {
for (let i=0, argsLen = args.length; i<argsLen; i++) {
if (i !== 0) {
writer.write(', ');
}
let arg = args[i];
if (!arg) {
throw new Error('Arg ' + i + ' is not valid for new expression: ' + JSON.stringify(this.toJSON()));
}
writer.write(arg);
}
}
writer.write(')');
}
isCompoundExpression() {
return true;
}
toJSON() {
return {
type: 'NewExpression',
callee: this.callee,
args: this.args
};
}
walk(walker) {
this.callee = walker.walk(this.callee);
this.args = walker.walk(this.args);
}
toString() {
var callee = this.callee;
var args = this.args;
let result = 'new ';
var wrap = isCompoundExpression(callee);
if (wrap) {
result += '(';
}
result += callee;
if (wrap) {
result += ')';
}
result += '(';
if (args && args.length) {
for (let i=0, argsLen = args.length; i<argsLen; i++) {
if (i !== 0) {
result += ', ';
}
let arg = args[i];
result += arg;
}
}
result += ')';
return result;
}
}
module.exports = NewExpression;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 | 1 1 1 1 1 1 1 6 6 6 6 6 6 6 6 6 6 6 6 6 6 1 | 'use strict';
var Container = require('./Container');
var ArrayContainer = require('./ArrayContainer');
var ok = require('assert').ok;
var extend = require('raptor-util/extend');
var inspect = require('util').inspect;
var EventEmitter = require('events').EventEmitter;
function trim(textNode) {
if (textNode.preserveWhitespace === true) {
return;
}
var text = textNode.argument.value;
var isFirst = textNode.isFirst;
var isLast = textNode.isLast;
if (isFirst) {
//First child
text = text.replace(/^\r?\n\s*/g, '');
}
if (isLast) {
//Last child
text = text.replace(/\r?\n\s*$/g, '');
}
if (/^\r?\n\s*$/.test(text)) {
//Whitespace between elements
text = '';
}
text = text.replace(/\s+/g, ' ');
textNode.argument.value = text;
}
class Node {
constructor(type) {
this.type = type;
this.statement = false;
this.container = null;
this.pos = null; // The character index of the node in the original source file
this.tagDef = null; // The tag definition associated with this Node
this._codeGeneratorFuncs = null;
this._flags = {};
this._transformersApplied = {};
this._preserveWhitespace = null;
this._events = null;
this._childTextNormalized = undefined;
this.data = {};
this._finalNode = false;
this._trimStartEnd = false;
}
on(event, listener) {
if (!this._events) {
this._events = new EventEmitter();
}
this._events.on(event, listener);
}
emit(event, args) {
if (this._events) {
this._events.emit.apply(this._events, arguments);
}
}
listenerCount(event) {
if (this._events) {
return this._events.listenerCount(event);
} else {
return 0;
}
}
onBeforeGenerateCode(listener) {
this.on('beforeGenerateCode', listener);
}
onAfterGenerateCode(listener) {
this.on('afterGenerateCode', listener);
}
wrapWith(wrapperNode) {
ok(this.container, 'Node does not belong to a container: ' + this);
var replaced = this.container.replaceChild(wrapperNode, this);
ok(replaced, 'Invalid state. Child does not belong to the container');
wrapperNode.appendChild(this);
}
replaceWith(newNode) {
ok(this.container, 'Node does not belong to a container: ' + this);
var replaced = this.container.replaceChild(newNode, this);
ok(replaced, 'Invalid state. Child does not belong to the container');
}
insertSiblingBefore(newNode) {
ok(this.container, 'Node does not belong to a container: ' + this);
this.container.insertChildBefore(newNode, this);
}
insertSiblingAfter(newNode) {
ok(this.container, 'Node does not belong to a container: ' + this);
this.container.insertChildAfter(newNode, this);
}
/**
* Converts the provided `array` into a `ArrayContainer`. If the provided `array` is already an instance of a `Container` then it is simply returned.
* @param {[type]} array [description]
* @return {[type]} [description]
*/
makeContainer(array) {
if (array instanceof Container) {
return array;
}
return new ArrayContainer(this, array);
}
prependChild(node) {
ok(this.body, 'Node does not support child nodes: ' + this);
this.body.prependChild(node);
}
appendChild(node) {
ok(this.body, 'Node does not support child nodes: ' + this);
this.body.appendChild(node);
}
insertBefore(newNode, referenceNode) {
ok(this.body, 'Node does not support child nodes: ' + this);
this.body.insertBefore(newNode, referenceNode);
}
forEachChild(callback, thisObj) {
if (this.body) {
this.body.forEach(callback, thisObj);
}
}
moveChildrenTo(targetNode) {
ok(this.body, 'Node does not support child nodes: ' + this);
ok(this !== targetNode, 'Target node cannot be the same as the source node');
this.body.moveChildrenTo(targetNode);
}
forEachNextSibling(callback, thisObj) {
var container = this.container;
if (container) {
container.forEachNextSibling(this, callback, thisObj);
}
}
get firstChild() {
var body = this.body;
return body && body.firstChild;
}
get previousSibling() {
var container = this.container;
if (container) {
return container.getPreviousSibling(this);
}
}
get nextSibling() {
var container = this.container;
if (container) {
return container.getNextSibling(this);
}
}
isTransformerApplied(transformer) {
return this._transformersApplied[transformer.id] === true;
}
setTransformerApplied(transformer) {
this._transformersApplied[transformer.id] = true;
}
toString() {
return inspect(this);
}
toJSON() {
let result = extend({}, this);
delete result.container;
delete result.statement;
delete result.pos;
delete result._transformersApplied;
delete result._codeGeneratorFuncs;
delete result._flags;
delete result.data;
delete result.tagDef;
delete result._preserveWhitespace;
delete result._events;
delete result._finalNode;
delete result._trimStartEnd;
delete result._childTextNormalized;
return result;
}
detach() {
if (this.container) {
this.container.removeChild(this);
this.container = null;
}
}
/**
* Returns true if the current node represents a compound expression (e.g. )
* @return {Boolean} [description]
*/
isCompoundExpression() {
return false;
}
isDetached() {
return this.container == null;
}
/**
* Used by the Node.js require('util').inspect function.
* We default to inspecting on the simplified version
* of this node that is the same version we use when
* serializing to JSON.
*/
inspect(depth, opts) {
// We inspect in the simplified version of this object t
return this.toJSON();
}
setType(newType) {
this.type = newType;
}
setCodeGenerator(mode, codeGeneratorFunc) {
if (arguments.length === 1) {
codeGeneratorFunc = arguments[0];
mode = null;
}
if (!this._codeGeneratorFuncs) {
this._codeGeneratorFuncs = {};
}
this._codeGeneratorFuncs[mode || 'DEFAULT'] = codeGeneratorFunc;
}
getCodeGenerator(mode) {
if (this._codeGeneratorFuncs) {
return this._codeGeneratorFuncs[mode] || this._codeGeneratorFuncs.DEFAULT;
} else {
return undefined;
}
}
setFlag(name) {
this._flags[name] = true;
}
clearFlag(name) {
delete this._flags[name];
}
isFlagSet(name) {
return this._flags.hasOwnProperty(name);
}
get bodyText() {
var bodyText = '';
this.forEachChild((child) => {
if (child.type === 'Text') {
var childText = child.argument;
if (childText && childText.type === 'Literal') {
bodyText += childText.value;
}
}
});
return bodyText;
}
get parentNode() {
return this.container && this.container.node;
}
setPreserveWhitespace(isPreserved) {
this._preserveWhitespace = isPreserved;
}
isPreserveWhitespace() {
var preserveWhitespace = this._preserveWhitespace;
if (preserveWhitespace == null) {
preserveWhitespace = this.tagDef && this.tagDef.preserveWhitespace;
}
return preserveWhitespace === true;
}
setFinalNode(isFinal) {
this._finalNode = true;
}
setTrimStartEnd(trimStartEnd) {
this._trimStartEnd = trimStartEnd;
}
_normalizeChildTextNodes(context, forceTrim) {
if (this._childTextNormalized) {
return;
}
this._childTextNormalized = true;
var trimStartEnd = this._trimStartEnd === true;
var isPreserveWhitespace = false;
if (!forceTrim) {
if (context.isPreserveWhitespace() || this.preserveWhitespace === true || this.isPreserveWhitespace()) {
isPreserveWhitespace = true;
}
}
if (isPreserveWhitespace && trimStartEnd !== true) {
return;
}
var body = this.body;
if (!body) {
return;
}
var isFirst = true;
var currentTextLiteral = null;
var literalTextNodes = [];
body.forEach((curChild, i) => {
if (curChild.noOutput) {
// Skip over AST nodes that produce no HTML output
return;
}
if (curChild.type === 'Text' && curChild.isLiteral()) {
curChild.isFirst = null;
curChild.isLast = null;
if (currentTextLiteral &&
currentTextLiteral.preserveWhitespace === curChild.preserveWhitespace &&
currentTextLiteral.escape === curChild.escape) {
currentTextLiteral.argument.value += curChild.argument.value;
curChild.detach();
} else {
currentTextLiteral = curChild;
literalTextNodes.push(currentTextLiteral);
if (isFirst) {
currentTextLiteral.isFirst = true;
}
}
} else {
currentTextLiteral = null;
}
isFirst = false;
});
if (currentTextLiteral) {
// Last child text
currentTextLiteral.isLast = true;
}
if (trimStartEnd) {
if (literalTextNodes.length) {
// We will only trim the first and last nodes
var firstTextNode = literalTextNodes[0];
var lastTextNode = literalTextNodes[literalTextNodes.length - 1];
if (firstTextNode.isFirst) {
firstTextNode.argument.value = firstTextNode.argument.value.replace(/^\s*/, '');
}
if (lastTextNode.isLast) {
lastTextNode.argument.value = lastTextNode.argument.value.replace(/\s*$/, '');
}
}
}
if (!isPreserveWhitespace) {
literalTextNodes.forEach(trim);
}
literalTextNodes.forEach((textNode) => {
if (textNode.argument.value === '') {
textNode.detach();
}
});
}
get childCount() {
ok(this.body, 'Node does not support child nodes: ' + this);
return this.body.length;
}
}
module.exports = Node;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | 1 1 | 'use strict';
var Node = require('./Node');
class ObjectExpression extends Node {
constructor(def) {
super('ObjectExpression');
this.properties = def.properties;
}
generateCode(codegen) {
this.properties = codegen.generateCode(this.properties);
return this;
}
writeCode(writer) {
var properties = this.properties;
if (!properties || !properties.length) {
writer.write('{}');
return;
}
writer.incIndent();
writer.write('{\n');
writer.incIndent();
properties.forEach((prop, i) => {
writer.writeLineIndent();
writer.write(prop);
if (i < properties.length - 1) {
writer.write(',\n');
} else {
writer.write('\n');
}
});
writer.decIndent();
writer.writeLineIndent();
writer.write('}');
writer.decIndent();
}
toJSON() {
return {
type: 'ObjectExpression',
properties: this.properties
};
}
walk(walker) {
this.properties = walker.walk(this.properties);
}
toString(codegen) {
var properties = this.properties;
if (!properties || !properties.length) {
return '{}';
}
let result = '{';
properties.forEach((prop, i) => {
if (i !== 0) {
result += ', ';
}
result += prop;
});
return result + '}'; }
}
module.exports = ObjectExpression;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 1 1 | 'use strict';
var Node = require('./Node');
class Program extends Node {
constructor(def) {
super('Program');
this.body = def.body;
}
generateCode(codegen) {
this.body = codegen.generateCode(this.body);
return this;
}
writeCode(writer) {
writer.writeStatements(this.body);
}
walk(walker) {
this.body = walker.walk(this.body);
}
}
module.exports = Program;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | 1 1 1 | 'use strict';
const isValidJavaScriptIdentifier = require('../util/isValidJavaScriptIdentifier');
const Node = require('./Node');
class Property extends Node {
constructor(def) {
super('Property');
this.key = def.key;
this.value = def.value;
}
generateCode(codegen) {
var key = this.key;
var value = this.value;
if (key.type === 'Literal') {
var propName = key.value;
if (isValidJavaScriptIdentifier(propName)) {
key = codegen.builder.identifier(propName);
}
}
this.key = codegen.generateCode(key);
this.value = codegen.generateCode(value);
return this;
}
writeCode(writer) {
var key = this.key;
var value = this.value;
writer.write(key);
writer.write(': ');
writer.write(value);
}
toJSON() {
return {
type: 'Property',
key: this.key,
value: this.value
};
}
walk(walker) {
this.key = walker.walk(this.key);
this.value = walker.walk(this.value);
}
toString() {
var key = this.key;
var value = this.value;
if (key.type === 'Literal') {
var propName = key.value;
if (isValidJavaScriptIdentifier(propName)) {
key = propName;
}
}
return key + ': ' + value;
}
}
module.exports = Property;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 1 1 | 'use strict';
var Node = require('./Node');
class Return extends Node {
constructor(def) {
super('Return');
this.argument = def.argument;
}
generateCode(codegen) {
if (!codegen.inFunction) {
throw new Error('"return" not allowed outside a function body');
}
this.argument = codegen.generateCode(this.argument);
return this;
}
writeCode(writer) {
var argument = this.argument;
if (argument) {
writer.write('return ');
writer.write(argument);
} else {
writer.write('return');
}
}
walk(walker) {
this.argument = walker.walk(this.argument);
}
}
module.exports = Return;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 1 1 1 | 'use strict';
var Node = require('./Node');
var adjustIndent = require('../util/adjustIndent');
class Scriptlet extends Node {
constructor(def) {
super('Scriptlet');
this.code = def.code;
this.tag = def.tag;
this.block = def.block;
}
generateCode(codegen) {
return this;
}
writeCode(writer) {
var code = this.code;
if (!code) {
return;
}
code = adjustIndent(code, writer.currentIndent);
writer.write(code);
writer.write('\n');
}
}
module.exports = Scriptlet;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 1 1 | 'use strict';
var Node = require('./Node');
class SelfInvokingFunction extends Node {
constructor(def) {
super('SelfInvokingFunction');
this.params = def.params;
this.args = def.args;
this.body = this.makeContainer(def.body);
}
generateCode(codegen) {
var params = this.params || [];
var args = this.args || [];
var oldInFunction = codegen.inFunction;
codegen.inFunction = true;
var body = codegen.generateCode(this.body);
codegen.inFunction = oldInFunction;
var functionDeclaration = codegen.builder.functionDeclaration(null, params, body);
var functionCall = codegen.builder.functionCall(functionDeclaration, args);
return functionCall;
}
walk(walker) {
this.params = walker.walk(this.params);
this.args = walker.walk(this.args);
this.body = walker.walk(this.body);
}
}
module.exports = SelfInvokingFunction;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | 1 1 | 'use strict';
var Node = require('./Node');
class SequenceExpression extends Node {
constructor(def) {
super('SequenceExpression');
this.expressions = def.expressions;
}
generateCode(codegen) {
this.expressions = codegen.generateCode(this.expressions);
return this;
}
writeCode(writer) {
for (var i=0; i<this.expressions.length; i++) {
var expression = this.expressions[i];
if (i !== 0) {
writer.write(', ');
}
writer.write(expression);
}
}
isCompoundExpression() {
return true;
}
toJSON() {
return {
type: 'SequenceExpression',
expressions: this.expressions
};
}
walk(walker) {
this.expressions = walker.walk(this.expressions);
}
toString() {
var code = '';
for (var i=0; i<this.expressions.length; i++) {
var expression = this.expressions[i];
if (i !== 0) {
code += ', ';
}
code += expression;
}
return code;
}
}
module.exports = SequenceExpression;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | 1 1 1 1 | 'use strict';
var Node = require('./Node');
function createVarsArray(vars) {
return Object.keys(vars).map(function(varName) {
var varInit = vars[varName];
return {
id: varName,
init: varInit
};
});
}
function _buildVersionComment(builder, context) {
const version = context.compilerVersion;
const compilerType = context.compilerType;
return builder.comment(`Compiled using ${compilerType}@${version} - DO NOT EDIT`);
}
class TemplateRoot extends Node {
constructor(def) {
super('TemplateRoot');
this.body = this.makeContainer(def.body);
this.extraRenderParams = null;
this.generateAssignRenderCode = null;
}
addRenderFunctionParam(id) {
if (!this.extraRenderParams) {
this.extraRenderParams = [];
}
this.extraRenderParams.push(id);
}
generateCode(codegen) {
var context = codegen.context;
this.body = codegen.generateCode(this.body);
context.optimize(this);
var body = this.body;
var builder = codegen.builder;
let renderStatements = [
builder.var('data', builder.identifier('input'))
];
var vars = createVarsArray(context.getVars());
if (vars.length) {
renderStatements.push(builder.vars(vars));
}
renderStatements = renderStatements.concat(body);
if (context.inline) {
var createInlineMarkoTemplateVar = context.helper('createInlineTemplate');
return builder.functionCall(
createInlineMarkoTemplateVar,
[
builder.identifier('__filename'),
builder.functionDeclaration(
null,
[
builder.identifier('input'),
builder.identifierOut()
],
renderStatements)
]);
} else {
var isBrowser = context.options.browser;
var createArgs = isBrowser ?
[] :
[ builder.identifier('__filename') ];
let templateDeclaration = builder.variableDeclarator('marko_template',
builder.assignment(
builder.moduleExports(),
builder.functionCall(
builder.memberExpression(
builder.require(
builder.literal(context.getModuleRuntimeTarget())
),
builder.identifier('t')
),
createArgs
)
)
);
let body = [];
if (context.writeVersionComment) {
body.push(_buildVersionComment(builder, context));
}
body.push(builder.literal('use strict'));
let staticNodes = context.getStaticNodes([templateDeclaration]);
if (staticNodes.length) {
body = body.concat(staticNodes);
}
var renderParams = [builder.identifier('input'), builder.identifierOut()];
if (this.extraRenderParams) {
renderParams = renderParams.concat(this.extraRenderParams);
}
let renderFunction = builder.functionDeclaration(
'render',
renderParams,
renderStatements);
body = body.concat([
renderFunction,
]);
var assignRenderCode;
let templateVar = builder.identifier('marko_template');
let renderFunctionVar = builder.identifier('render');
let templateRendererMember = builder.memberExpression(
builder.identifier('marko_template'),
builder.identifier('_'));
if (this.generateAssignRenderCode) {
var eventArgs = {
context,
templateVar,
templateRendererMember,
renderFunctionVar
};
assignRenderCode = this.generateAssignRenderCode(eventArgs);
} else {
assignRenderCode = builder.assignment(
templateRendererMember,
renderFunctionVar);
}
if (assignRenderCode) {
body = body.concat(assignRenderCode);
}
if (context.useMeta && context.meta) {
body.push(builder.assignment(
builder.memberExpression(builder.identifier('marko_template'), builder.identifier('meta')),
builder.literal(context.meta)));
}
return builder.program(body);
}
}
toJSON(prettyPrinter) {
return {
type: this.type,
body: this.body
};
}
walk(walker) {
this.body = walker.walk(this.body);
}
}
module.exports = TemplateRoot;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 1 1 | 'use strict';
var Node = require('./Node');
class ThisExpression extends Node {
constructor(def) {
super('ThisExpression');
}
generateCode(codegen) {
return this;
}
writeCode(writer) {
writer.write('this');
}
toString() {
return 'this';
}
}
module.exports = ThisExpression;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | 1 1 1 | 'use strict';
var Node = require('./Node');
var isCompoundExpression = require('../util/isCompoundExpression');
class UnaryExpression extends Node {
constructor(def) {
super('UnaryExpression');
this.argument = def.argument;
this.operator = def.operator;
this.prefix = def.prefix === true;
}
generateCode(codegen) {
this.argument = codegen.generateCode(this.argument);
return this;
}
writeCode(writer) {
var argument = this.argument;
var operator = this.operator;
var prefix = this.prefix;
if (prefix) {
writer.write(operator);
if (operator === 'typeof' || operator === 'delete') {
writer.write(' ');
}
}
var wrap = isCompoundExpression(argument);
if (wrap) {
writer.write('(');
}
writer.write(argument);
if (wrap) {
writer.write(')');
}
if (!prefix) {
writer.write(operator);
}
}
isCompoundExpression() {
return true;
}
toJSON() {
return {
type: 'UnaryExpression',
argument: this.argument,
operator: this.operator,
prefix: this.prefix
};
}
walk(walker) {
this.argument = walker.walk(this.argument);
}
toString() {
var argument = this.argument;
var operator = this.operator;
var prefix = this.prefix;
let result = '';
if (prefix) {
result += operator;
if (operator === 'typeof' || operator === 'delete') {
result += ' ';
}
}
var wrap = isCompoundExpression(argument);
if (wrap) {
result += '(';
}
result += argument;
if (wrap) {
result += ')';
}
if (!prefix) {
result += operator;
}
return result;
}
}
module.exports = UnaryExpression;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | 1 1 1 | 'use strict';
var Node = require('./Node');
var isCompoundExpression = require('../util/isCompoundExpression');
class UpdateExpression extends Node {
constructor(def) {
super('UpdateExpression');
this.argument = def.argument;
this.operator = def.operator;
this.prefix = def.prefix === true;
}
generateCode(codegen) {
this.argument = codegen.generateCode(this.argument);
return this;
}
writeCode(writer) {
var argument = this.argument;
var operator = this.operator;
var prefix = this.prefix;
if (prefix) {
writer.write(operator);
}
var wrap = isCompoundExpression(argument);
if (wrap) {
writer.write('(');
}
writer.write(argument);
if (wrap) {
writer.write(')');
}
if (!prefix) {
writer.write(operator);
}
}
isCompoundExpression() {
return true;
}
toJSON() {
return {
type: 'UpdateExpression',
argument: this.argument,
operator: this.operator,
prefix: this.prefix
};
}
walk(walker) {
this.argument = walker.walk(this.argument);
}
toString() {
var argument = this.argument;
var operator = this.operator;
var prefix = this.prefix;
let result = '';
if (prefix) {
result += operator;
}
var wrap = isCompoundExpression(argument);
if (wrap) {
result += '(';
}
result += argument;
if (wrap) {
result += ')';
}
if (!prefix) {
result += operator;
}
return result;
}
}
module.exports = UpdateExpression;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | 1 1 1 1 | 'use strict';
var Node = require('./Node');
var Identifier = require('./Identifier');
var isValidJavaScriptVarName = require('../util/isValidJavaScriptVarName');
class VariableDeclarator extends Node {
constructor(def) {
super('VariableDeclarator');
this.id = def.id;
this.init = def.init;
let name = this.id.name;
if (!name) {
throw new Error('"name" is required');
}
if (!isValidJavaScriptVarName(name)) {
var error = new Error('Invalid JavaScript variable name: ' + name);
error.code = 'INVALID_VAR_NAME';
throw error;
}
}
generateCode(codegen) {
this.id = codegen.generateCode(this.id);
this.init = codegen.generateCode(this.init);
return this;
}
writeCode(writer) {
var id = this.id;
var init = this.init;
if (!(id instanceof Identifier) && typeof id !== 'string') {
throw new Error('Invalid variable name: ' + id);
}
writer.write(id);
if (init != null) {
writer.write(' = ');
writer.write(init);
}
}
walk(walker) {
this.id = walker.walk(this.id);
this.init = walker.walk(this.init);
}
}
module.exports = VariableDeclarator;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | 1 1 | 'use strict';
var Node = require('./Node');
class Vars extends Node {
constructor(def) {
super('Vars');
this.kind = def.kind || 'var';
this.declarations = def.declarations;
this.body = this.makeContainer(def.body);
}
generateCode(codegen) {
var declarations = this.declarations;
if (!declarations || !declarations.length) {
return null;
}
this.declarations = codegen.generateCode(this.declarations);
if (this.body && this.body.length) {
var scopedBody = [this].concat(this.body);
this.body = null;
return codegen.builder.selfInvokingFunction(scopedBody);
}
return this;
}
writeCode(writer) {
var declarations = this.declarations;
var kind = this.kind;
var isStatement = this.statement;
if (!declarations || !declarations.length) {
return;
}
writer.incIndent(4);
for (let i=0; i<declarations.length; i++) {
var declarator = declarations[i];
if (i === 0) {
writer.write(kind + ' ');
} else {
writer.writeLineIndent();
}
writer.write(declarator);
if (i < declarations.length - 1) {
writer.write(',\n');
} else {
if (isStatement) {
writer.write(';\n');
}
}
}
writer.decIndent(4);
}
walk(walker) {
this.argument = walker.walk(this.argument);
}
/**
* "noOutput" should be true if the Node.js does not result in any HTML or Text output
*/
get noOutput() {
return !(this.body && this.body.length);
}
}
module.exports = Vars;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 1 1 | 'use strict';
var Node = require('./Node');
class WhileStatement extends Node {
constructor(def) {
super('WhileStatement');
this.test = def.test;
this.body = this.makeContainer(def.body);
}
generateCode(codegen) {
this.test = codegen.generateCode(this.test);
this.body = codegen.generateCode(this.body);
return this;
}
writeCode(writer) {
var test = this.test;
var body = this.body;
writer.write('while (');
writer.write(test);
writer.write(') ');
writer.write(body);
writer.write('\n');
}
walk(walker) {
this.test = walker.walk(this.test);
this.body = walker.walk(this.body);
}
}
module.exports = WhileStatement;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 28.95% | (11 / 38) | 0% | (0 / 12) | 0% | (0 / 11) | 28.95% | (11 / 38) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var Node = require('../Node');
var Literal = require('../Literal');
var ok = require('assert').ok;
var compiler = require('../../');
var generateHTMLCode = require('./html/generateCode');
var generateVDOMCode = require('./vdom/generateCode');
var vdomUtil = require('../../util/vdom');
function beforeGenerateCode(event) {
event.codegen.isInAttribute = true;
}
function afterGenerateCode(event) {
event.codegen.isInAttribute = false;
}
class HtmlAttribute extends Node {
constructor(def) {
super('HtmlAttribute');
ok(def, 'Invalid attribute definition');
this.type = 'HtmlAttribute';
this.name = def.name;
this.value = def.value;
this.rawValue = def.rawValue;
this.escape = def.escape;
if (typeof this.value === 'string') {
this.value = compiler.builder.parseExpression(this.value);
}
if (this.value && !(this.value instanceof Node)) {
throw new Error('"value" should be a Node instance');
}
this.argument = def.argument;
this.def = def.def; // The attribute definition loaded from the taglib (if any)
this.on('beforeGenerateCode', beforeGenerateCode);
this.on('afterGenerateCode', afterGenerateCode);
}
generateHTMLCode(codegen) {
return generateHTMLCode(this, codegen);
}
generateVDOMCode(codegen) {
return generateVDOMCode(this, codegen, vdomUtil);
}
isLiteralValue() {
return this.value instanceof Literal;
}
isLiteralString() {
return this.isLiteralValue() &&
typeof this.value.value === 'string';
}
isLiteralBoolean() {
return this.isLiteralValue() &&
typeof this.value.value === 'boolean';
}
walk(walker) {
this.value = walker.walk(this.value);
}
get literalValue() {
if (this.isLiteralValue()) {
return this.value.value;
} else {
throw new Error('Attribute value is not a literal value. Actual: ' + JSON.stringify(this.value, null, 2));
}
}
}
HtmlAttribute.isHtmlAttribute = function(attr) {
return (attr instanceof HtmlAttribute);
};
module.exports = HtmlAttribute;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| generateCode.js | 14.67% | (11 / 75) | 0% | (0 / 48) | 0% | (0 / 8) | 14.67% | (11 / 75) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var runtimeHtmlHelpers = require('../../../../runtime/html/helpers');
var attr = runtimeHtmlHelpers.a;
var escapeXmlAttr = runtimeHtmlHelpers.xa;
function isStringLiteral(node) {
return node.type === 'Literal' && typeof node.value === 'string';
}
function isNoEscapeXml(node) {
return node.type === 'AttributePlaceholder' &&
node.escape === false;
}
function flattenAttrConcats(node) {
// return [node];
function flattenHelper(node) {
if (node.type === 'BinaryExpression' && node.operator === '+') {
let left = flattenHelper(node.left);
let right = flattenHelper(node.right);
var isString = left.isString || right.isString;
if (isString) {
return {
isString: true,
concats: left.concats.concat(right.concats)
};
} else {
return {
isString: false,
concats: [node]
};
}
}
return {
isString: isStringLiteral(node) || node.type === 'AttributePlaceholder',
concats: [node]
};
}
var final = flattenHelper(node);
return final.concats;
}
function generateCodeForExpressionAttr(name, value, escape, codegen) {
var flattenedConcats = flattenAttrConcats(value);
var hasLiteral = false;
var builder = codegen.builder;
var finalNodes = [];
var context = codegen.context;
function addHtml(argument) {
finalNodes.push(builder.html(argument));
}
function addHtmlLiteral(value) {
finalNodes.push(builder.htmlLiteral(value));
}
for (let i=0; i<flattenedConcats.length; i++) {
if (flattenedConcats[i].type === 'Literal' || flattenedConcats[i].type === 'AttributePlaceholder') {
hasLiteral = true;
break;
}
}
if (hasLiteral) {
addHtmlLiteral(' ' + name + '="');
for (let i=0; i<flattenedConcats.length; i++) {
var part = flattenedConcats[i];
if (isStringLiteral(part)) {
part.value = escapeXmlAttr(part.value);
} else if (part.type === 'Literal') {
} else if (isNoEscapeXml(part)) {
part = codegen.builder.functionCall(context.helper('str'), [part]);
} else {
if (escape !== false) {
part = builder.functionCall(context.helper('escapeXmlAttr'), [part]);
}
}
addHtml(part);
}
addHtmlLiteral('"');
} else {
if (name === 'class') {
addHtml(codegen.builder.functionCall(context.helper('classAttr'), [value]));
} else if (name === 'style') {
addHtml(codegen.builder.functionCall(context.helper('styleAttr'), [value]));
} else {
if (escape === false || isNoEscapeXml(value)) {
escape = false;
}
let attrArgs = [codegen.builder.literal(name), value];
if (escape === false) {
attrArgs.push(codegen.builder.literal(false));
}
addHtml(codegen.builder.functionCall(context.helper('attr'), attrArgs));
}
}
return finalNodes;
}
module.exports = function generateCode(node, codegen) {
let name = node.name;
let value = node.value;
let argument = node.argument;
let escape = node.escape !== false;
var builder = codegen.builder;
if (!name) {
return null;
}
if (node.isLiteralValue()) {
let literalValue = value.value;
if (literalValue instanceof RegExp) {
literalValue = literalValue.source;
}
return builder.htmlLiteral(attr(name, literalValue));
} else if (value != null) {
return generateCodeForExpressionAttr(name, value, escape, codegen);
} else if (argument) {
return [
builder.htmlLiteral(' ' + name + '('),
builder.htmlLiteral(argument),
builder.htmlLiteral(')')
];
} else {
// Attribute with no value is a boolean attribute
return builder.htmlLiteral(' ' + name);
}
};
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| generateCode.js | 5.88% | (1 / 17) | 0% | (0 / 10) | 0% | (0 / 1) | 5.88% | (1 / 17) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 1 | 'use strict'; module.exports = function generateCode(node, codegen, vdomUtil) { var context = codegen.context; var builder = codegen.builder; // node.name = codegen.generateCode(node.name); node.value = codegen.generateCode(node.value); node.isStatic = vdomUtil.isStaticValue(node.value); var name = node.name; var attrValue = node.value; if (attrValue) { if (attrValue.type === 'Literal') { var literalValue = attrValue.value; if (literalValue instanceof RegExp) { node.value = builder.literal(literalValue.source); } } else { if (name === 'class') { node.value = builder.functionCall(context.helper('classAttr'), [attrValue]); } else if (name === 'style') { node.value = builder.functionCall(context.helper('styleAttr'), [attrValue]); } } } return node; }; |
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 9.57% | (9 / 94) | 0% | (0 / 48) | 0% | (0 / 25) | 9.57% | (9 / 94) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | 1 1 1 1 1 1 1 1 1 | 'use strict';
var Node = require('../Node');
var Literal = require('../Literal');
var HtmlAttributeCollection = require('../HtmlAttributeCollection');
var generateHTMLCode = require('./html/generateCode');
var generateVDOMCode = require('./vdom/generateCode');
var vdomUtil = require('../../util/vdom');
function beforeGenerateCode(event) {
var tagName = event.node.tagName;
var context = event.context;
var tagDef = typeof tagName === 'string' ? context.getTagDef(tagName) : undefined;
if (tagDef && tagDef.htmlType === 'svg') {
context.pushFlag('SVG');
}
if (tagName === 'script') {
context.pushFlag('SCRIPT_BODY');
}
if (tagName === 'style') {
context.pushFlag('STYLE_BODY');
}
}
function afterGenerateCode(event) {
var tagName = event.node.tagName;
var context = event.context;
var tagDef = typeof tagName === 'string' ? context.getTagDef(tagName) : undefined;
if (tagDef && tagDef.htmlType === 'svg') {
context.popFlag('SVG');
}
if (tagName === 'script') {
context.popFlag('SCRIPT_BODY');
}
if (tagName === 'style') {
context.popFlag('STYLE_BODY');
}
}
class HtmlElement extends Node {
constructor(def) {
super('HtmlElement');
this.tagName = null;
this.tagNameExpression = null;
this.setTagName(def.tagName);
this.tagString = def.tagString;
this._attributes = def.attributes;
this._properties = def.properties;
this.body = this.makeContainer(def.body);
this.argument = def.argument;
if (!(this._attributes instanceof HtmlAttributeCollection)) {
this._attributes = new HtmlAttributeCollection(this._attributes);
}
this.openTagOnly = def.openTagOnly;
this.selfClosed = def.selfClosed;
this.dynamicAttributes = undefined;
this.bodyOnlyIf = undefined;
this.on('beforeGenerateCode', beforeGenerateCode);
this.on('afterGenerateCode', afterGenerateCode);
}
generateHTMLCode(codegen) {
if (codegen.context.isMacro(this.tagName)) {
// At code generation time, if node tag corresponds to a registered macro
// then invoke the macro based on node HTML element instead of generating
// the code to render an HTML element.
return codegen.builder.invokeMacroFromEl(this);
}
return generateHTMLCode(this, codegen);
}
generateVDOMCode(codegen) {
if (codegen.context.isMacro(this.tagName)) {
// At code generation time, if node tag corresponds to a registered macro
// then invoke the macro based on node HTML element instead of generating
// the code to render an HTML element.
return codegen.builder.invokeMacroFromEl(this);
}
return generateVDOMCode(this, codegen, vdomUtil);
}
addDynamicAttributes(expression) {
if (!this.dynamicAttributes) {
this.dynamicAttributes = [];
}
this.dynamicAttributes.push(expression);
}
getAttribute(name) {
return this._attributes != null && this._attributes.getAttribute(name);
}
getAttributeValue(name) {
var attr = this._attributes != null && this._attributes.getAttribute(name);
if (attr) {
return attr.value;
}
}
addAttribute(attr) {
this._attributes.addAttribute(attr);
}
setAttributeValues(attrs) {
if (!attrs) {
return;
}
for(var attrName in attrs) {
var attrValue = attrs[attrName];
this.setAttributeValue(attrName, attrValue);
}
}
setAttributeValue(name, value, escape) {
this._attributes.setAttributeValue(name, value, escape);
}
setPropertyValue(name, value) {
if (!this._properties) {
this._properties = {};
}
this._properties[name] = value;
}
getProperties() {
return this._properties;
}
replaceAttributes(newAttributes) {
this._attributes.replaceAttributes(newAttributes);
}
removeAttribute(name) {
if (this._attributes) {
this._attributes.removeAttribute(name);
}
}
removeAllAttributes() {
this._attributes.removeAllAttributes();
}
hasAttribute(name) {
return this._attributes != null && this._attributes.hasAttribute(name);
}
getAttributes() {
return this._attributes.all;
}
get attributes() {
return this._attributes.all;
}
forEachAttribute(callback, thisObj) {
var attributes = this._attributes.all.concat([]);
for (let i=0, len=attributes.length; i<len; i++) {
callback.call(thisObj, attributes[i]);
}
}
setTagName(tagName) {
this.tagName = null;
this.tagNameExpression = null;
if (tagName instanceof Node) {
if (tagName instanceof Literal) {
this.tagName = tagName.value;
this.tagNameExpression = tagName;
} else {
this.tagNameExpression = tagName;
}
} else if (typeof tagName === 'string') {
this.tagNameExpression = new Literal({value: tagName});
this.tagName = tagName;
}
}
isLiteralTagName() {
return this.tagName != null;
}
toJSON() {
return {
type: this.type,
tagName: this.tagName,
attributes: this._attributes,
tagString: this.tagString,
argument: this.argument,
body: this.body,
bodyOnlyIf: this.bodyOnlyIf,
dynamicAttributes: this.dynamicAttributes
};
}
setBodyOnlyIf(condition) {
this.bodyOnlyIf = condition;
}
walk(walker) {
this.setTagName(walker.walk(this.tagNameExpression));
this._attributes.walk(walker);
this.body = walker.walk(this.body);
}
}
module.exports = HtmlElement;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| EndTag.js | 28.57% | (2 / 7) | 100% | (0 / 0) | 0% | (0 / 2) | 28.57% | (2 / 7) | |
| StartTag.js | 7.14% | (2 / 28) | 0% | (0 / 6) | 0% | (0 / 3) | 7.14% | (2 / 28) | |
| generateCode.js | 7.69% | (3 / 39) | 0% | (0 / 22) | 0% | (0 / 1) | 7.69% | (3 / 39) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 1 1 | 'use strict';
var Node = require('../../Node');
class EndTag extends Node {
constructor(def) {
super('EndTag');
this.tagName = def.tagName;
}
generateCode(codegen) {
var tagName = this.tagName;
var builder = codegen.builder;
return [
builder.htmlLiteral('</'),
builder.html(tagName),
builder.htmlLiteral('>')
];
}
}
module.exports = EndTag;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | 1 1 | 'use strict';
var Node = require('../../Node');
class StartTag extends Node {
constructor(def) {
super('StartTag');
this.tagName = def.tagName;
this.attributes = def.attributes;
this.properties = def.properties;
this.argument = def.argument;
this.selfClosed = def.selfClosed;
this.dynamicAttributes = def.dynamicAttributes;
}
generateCode(codegen) {
var builder = codegen.builder;
var tagName = this.tagName;
var selfClosed = this.selfClosed;
var dynamicAttributes = this.dynamicAttributes;
var context = codegen.context;
var nodes = [
builder.htmlLiteral('<'),
builder.html(tagName),
];
var attributes = this.attributes;
if (attributes) {
for (let i=0; i<attributes.length; i++) {
let attr = attributes[i];
nodes.push(codegen.generateCode(attr));
}
}
if (dynamicAttributes) {
dynamicAttributes.forEach(function(attrsExpression) {
let attrsFunctionCall = builder.functionCall(context.helper('attrs'), [attrsExpression]);
nodes.push(builder.html(attrsFunctionCall));
});
}
if (selfClosed) {
nodes.push(builder.htmlLiteral('/>'));
} else {
nodes.push(builder.htmlLiteral('>'));
}
return nodes;
}
}
module.exports = StartTag;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | 1 1 1 | 'use strict';
var StartTag = require('./StartTag');
var EndTag = require('./EndTag');
module.exports = function generateCode(node, codegen) {
var builder = codegen.builder;
var tagName = node.tagName;
// Convert the tag name into a Node so that we generate the code correctly
if (tagName) {
tagName = codegen.builder.literal(tagName);
} else {
tagName = node.tagNameExpression;
}
var properties = node.getProperties();
if (properties) {
var objectProps = Object.keys(properties).map((propName) => {
return builder.property(
builder.identifier(propName),
properties[propName]);
});
node.setAttributeValue('data-marko',
builder.objectExpression(objectProps),
false);
}
var attributes = node._attributes && node._attributes.all;
var body = node.body;
var argument = node.argument;
var hasBody = body && body.length;
var openTagOnly = node.openTagOnly;
var bodyOnlyIf = node.bodyOnlyIf;
var dynamicAttributes = node.dynamicAttributes;
var selfClosed = node.selfClosed === true;
if (hasBody) {
body = codegen.generateCode(body);
}
if (hasBody || bodyOnlyIf) {
openTagOnly = false;
selfClosed = false;
} else if (selfClosed){
openTagOnly = true;
}
var startTag = new StartTag({
tagName: tagName,
attributes: attributes,
properties: properties,
argument: argument,
selfClosed: selfClosed,
dynamicAttributes: dynamicAttributes
});
var endTag;
if (!openTagOnly) {
endTag = new EndTag({
tagName: tagName
});
}
if (bodyOnlyIf) {
var startIf = builder.ifStatement(builder.negate(bodyOnlyIf), [
startTag
]);
var endIf = builder.ifStatement(builder.negate(bodyOnlyIf), [
endTag
]);
return [
startIf,
body,
endIf
];
} else {
if (openTagOnly) {
return codegen.generateCode(startTag);
} else {
return [
startTag,
body,
endTag
];
}
}
};
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| EndElementVDOM.js | 50% | (2 / 4) | 100% | (0 / 0) | 0% | (0 / 2) | 50% | (2 / 4) | |
| HtmlElementVDOM.js | 5.84% | (9 / 154) | 0% | (0 / 96) | 0% | (0 / 6) | 5.84% | (9 / 154) | |
| generateCode.js | 8.93% | (5 / 56) | 0% | (0 / 33) | 0% | (0 / 3) | 8.93% | (5 / 56) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 1 1 | 'use strict';
const Node = require('../../Node');
class EndElementVDOM extends Node {
constructor() {
super('EndElementVDOM');
}
writeCode(writer) {
writer.write('out.ee()');
}
}
module.exports = EndElementVDOM;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 | 1 1 1 1 1 1 1 1 1 | 'use strict';
const Node = require('../../Node');
const vdomUtil = require('../../../util/vdom');
var FLAG_IS_SVG = 1;
var FLAG_IS_TEXTAREA = 2;
var FLAG_SIMPLE_ATTRS = 4;
function finalizeCreateArgs(createArgs, builder) {
var length = createArgs.length;
var lastArg;
for (var i=length-1; i>=0; i--) {
var arg = createArgs[i];
if (arg) {
lastArg = arg;
} else {
if (lastArg != null) {
if (i === 3) {
// Use a literal 0 for the flags
createArgs[i] = builder.literal(0);
} else {
createArgs[i] = builder.literalNull();
}
} else {
length--;
}
}
}
createArgs.length = length;
return createArgs;
}
const MAYBE_SVG = {
'a': true,
'script': true,
'style': true
};
const SIMPLE_ATTRS = {
'class': true,
'style': true,
'id': true
};
class HtmlElementVDOM extends Node {
constructor(def) {
super('HtmlElementVDOM');
this.tagName = def.tagName;
this.isStatic = def.isStatic;
this.isAttrsStatic = def.isAttrsStatic;
this.isHtmlOnly = def.isHtmlOnly;
this.attributes = def.attributes;
this.properties = def.properties;
this.body = def.body;
this.dynamicAttributes = def.dynamicAttributes;
this.isSVG = false;
this.isTextArea = false;
this.hasAttributes = false;
this.hasSimpleAttrs = false; // This will be set to true if the HTML element
// only attributes in the following set:
// ['id', 'style', 'class']
this.isChild = false;
this.createElementId = undefined;
this.attributesArg = undefined;
this.propertiesArg = undefined;
this.nextConstId = undefined;
}
generateCode(codegen) {
let context = codegen.context;
let builder = codegen.builder;
vdomUtil.registerOptimizer(context);
let tagName = this.tagName;
if (tagName.type === 'Literal' && typeof tagName.value === 'string') {
let tagDef = context.getTagDef(tagName.value);
if (tagDef) {
if (tagDef.htmlType === 'svg') {
this.isSVG = true;
} else {
if (MAYBE_SVG[tagName.value] && context.isFlagSet('SVG')) {
this.isSVG = true;
} else {
this.tagName = tagName = builder.literal(tagName.value.toUpperCase());
if (tagName.value === 'TEXTAREA') {
this.isTextArea = true;
}
}
}
}
} else {
if (context.isFlagSet('SVG')) {
this.isSVG = true;
} else {
this.tagName = builder.functionCall(
builder.memberExpression(
tagName,
builder.identifier('toUpperCase')),
[]);
}
}
let attributes = this.attributes;
let properties = this.properties;
let dynamicAttributes = this.dynamicAttributes;
let attributesArg = null;
var hasNamedAttributes = false;
var hasDynamicAttributes = dynamicAttributes != null && dynamicAttributes.length !== 0;
var hasSimpleAttrs = true;
if (properties && properties.noupdate) {
// Preserving attributes requires extra logic that we cannot
// shortcircuit
hasSimpleAttrs = false;
}
if (attributes != null && attributes.length !== 0) {
let addAttr = function(name, value) {
hasNamedAttributes = true;
if (!SIMPLE_ATTRS[name]) {
hasSimpleAttrs = false;
}
if (!attributesArg) {
attributesArg = {};
}
if (value.type === 'Literal') {
let literalValue = value.value;
if (literalValue == null || literalValue === false) {
return;
} else if (typeof literalValue === 'number') {
value.value = literalValue.toString();
}
} else if (value.type === 'AttributePlaceholder') {
value = codegen.builder.functionCall(context.helper('str'), [value]);
}
attributesArg[name] = value;
};
attributes.forEach((attr) => {
let value = attr.value;
if (value == null) {
value = builder.literal(true);
}
if (!attr.name) {
return;
}
addAttr(attr.name, value);
});
if (attributesArg) {
attributesArg = builder.literal(attributesArg);
}
}
if (hasDynamicAttributes) {
dynamicAttributes.forEach((attrs) => {
if (attributesArg) {
let mergeVar = context.helper('merge');
attributesArg = builder.functionCall(mergeVar, [
attributesArg, // Input props from the attributes take precedence
attrs
]);
} else {
attributesArg = attrs;
}
});
}
if (!this.isAttrsStatic && hasNamedAttributes && hasSimpleAttrs && !hasDynamicAttributes) {
this.hasSimpleAttrs = true;
}
this.hasAttributes = hasNamedAttributes || hasDynamicAttributes;
this.attributesArg = attributesArg;
return this;
}
walk(walker) {
this.tagName = walker.walk(this.tagName);
this.attributes = walker.walk(this.attributes);
this.body = walker.walk(this.body);
}
writeCode(writer) {
let builder = writer.builder;
let body = this.body;
let attributesArg = this.attributesArg;
let nextConstId = this.nextConstId;
let tagName = this.tagName;
let childCount = body && body.length;
let createArgs = new Array(5); // tagName, attributes, childCount, const ID, flags
createArgs[0] = tagName;
if (attributesArg) {
createArgs[1] = attributesArg;
}
if (childCount != null) {
createArgs[2] = builder.literal(childCount);
}
var flags = 0;
if (this.isSVG) {
flags |= FLAG_IS_SVG;
}
if (this.isTextArea) {
flags |= FLAG_IS_TEXTAREA;
}
if (this.hasSimpleAttrs) {
flags |= FLAG_SIMPLE_ATTRS;
}
if (flags) {
createArgs[3] = builder.literal(flags);
}
if (nextConstId) {
if (!this.properties) {
this.properties = {};
}
this.properties.c = nextConstId;
}
if (this.properties) {
createArgs[4] = builder.literal(this.properties);
}
// Remove trailing undefined arguments and convert non-trailing
// undefined elements to a literal null node
createArgs = finalizeCreateArgs(createArgs, builder);
let funcCall;
if (this.isChild) {
writer.write('.');
funcCall = builder.functionCall(
builder.identifier('e'),
createArgs);
} else if (this.isStatic && this.createElementId) {
funcCall = builder.functionCall(
this.createElementId,
createArgs);
} else if (this.isHtmlOnly) {
writer.write('out.');
funcCall = builder.functionCall(
builder.identifier('e'),
createArgs);
} else {
writer.write('out.');
funcCall = builder.functionCall(
builder.identifier('be'),
createArgs);
}
writer.write(funcCall);
if (body && body.length) {
writer.incIndent();
for(let i=0; i<body.length; i++) {
let child = body[i];
child.isChild = true;
writer.write('\n');
writer.writeLineIndent();
writer.write(child);
}
writer.decIndent();
}
}
}
module.exports = HtmlElementVDOM;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | 1 1 1 1 1 | 'use strict';
var HtmlElementVDOM = require('./HtmlElementVDOM');
var EndElementVDOM = require('./EndElementVDOM');
function checkAttributesStatic(attributes) {
if (attributes) {
for (let i=0; i<attributes.length; i++) {
let attr = attributes[i];
if (!attr.isStatic) {
return false;
}
}
}
return true;
}
function checkPropertiesStatic(properties, vdomUtil) {
if (properties) {
var keys = Object.keys(properties);
for (var i=0; i<keys.length; i++) {
var propName = keys[i];
var propValue = properties[propName];
var isStatic = vdomUtil.isStaticValue(propValue);
if (!isStatic) {
return false;
}
}
}
return true;
}
module.exports = function(node, codegen, vdomUtil) {
var body = codegen.generateCode(node.body);
var tagName = codegen.generateCode(node.tagNameExpression);
var attributes = codegen.generateCode(node.getAttributes());
var properties = codegen.generateCode(node.getProperties());
var dynamicAttributes = codegen.generateCode(node.dynamicAttributes);
var builder = codegen.builder;
var isAttrsStatic = checkAttributesStatic(attributes);
var isPropsStatic = checkPropertiesStatic(properties, vdomUtil);
var isStatic = isAttrsStatic && isPropsStatic && node.isLiteralTagName();
var isHtmlOnly = true;
if (body && body.length) {
for (var i=0; i<body.length; i++) {
let child = body[i];
if (child.type === 'HtmlElementVDOM' || child.type === 'TextVDOM') {
if (child.type === 'TextVDOM' && child.escape === false) {
isHtmlOnly = false;
}
if (!child.isHtmlOnly) {
isStatic = false;
isHtmlOnly = false;
} if (!child.isStatic) {
isStatic = false;
}
} else {
isHtmlOnly = false;
isStatic = false;
}
}
}
var bodyOnlyIf = node.bodyOnlyIf;
if (bodyOnlyIf) {
isHtmlOnly = false;
}
var htmlElVDOM = new HtmlElementVDOM({
tagName,
attributes,
properties,
body,
isStatic,
isAttrsStatic,
isHtmlOnly,
dynamicAttributes
});
if (bodyOnlyIf) {
htmlElVDOM.body = null;
var startIf = builder.ifStatement(builder.negate(bodyOnlyIf), [
htmlElVDOM
]);
var endIf = builder.ifStatement(builder.negate(bodyOnlyIf), [
new EndElementVDOM()
]);
return [
startIf,
body,
endIf
];
} else if (isHtmlOnly) {
return htmlElVDOM;
} else {
htmlElVDOM.body = null;
return [htmlElVDOM].concat(body, new EndElementVDOM());
}
};
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 33.33% | (7 / 21) | 0% | (0 / 5) | 0% | (0 / 6) | 33.33% | (7 / 21) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | 1 1 1 1 1 1 1 | 'use strict';
var ok = require('assert').ok;
var Node = require('../Node');
var Literal = require('../Literal');
var generateHTMLCode = require('./html/generateCode');
var generateVDOMCode = require('./vdom/generateCode');
var vdomUtil = require('../../util/vdom');
class Text extends Node {
constructor(def) {
super('Text');
this.argument = def.argument;
this.escape = def.escape !== false;
this.normalized = false;
this.isFirst = false;
this.isLast = false;
this.preserveWhitespace = def.preserveWhitespace === true;
ok(this.argument, 'Invalid argument');
}
generateHTMLCode(codegen) {
return generateHTMLCode(this, codegen);
}
generateVDOMCode(codegen) {
return generateVDOMCode(this, codegen, vdomUtil);
}
isLiteral() {
return this.argument instanceof Node && this.argument.type === 'Literal';
}
isWhitespace() {
var argument = this.argument;
return (argument instanceof Literal) &&
(typeof argument.value === 'string') &&
(argument.value.trim() === '');
}
toJSON() {
return {
type: this.type,
argument: this.argument
};
}
}
module.exports = Text;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| generateCode.js | 12.5% | (4 / 32) | 0% | (0 / 20) | 0% | (0 / 2) | 12.5% | (4 / 32) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | 1 1 1 1 | 'use strict';
var escapeXml = require('../../../../runtime/html/helpers').x;
var Literal = require('../../Literal');
module.exports = function(node, codegen) {
var context = codegen.context;
var argument = codegen.generateCode(node.argument);
var escape = node.escape !== false;
var htmlArray = [];
function append(argument) {
if (argument instanceof Literal) {
if (!argument.value) {
return;
}
if (context.isFlagSet('SCRIPT_BODY') || context.isFlagSet('STYLE_BODY')) {
escape = false;
}
if (escape === true) {
argument.value = escapeXml(argument.value.toString());
}
htmlArray.push(argument);
} else {
let builder = codegen.builder;
if (escape) {
let escapeIdentifier = context.helper('escapeXml');
if (context.isFlagSet('SCRIPT_BODY')) {
escapeIdentifier = context.helper('escapeScript');
}
if (context.isFlagSet('STYLE_BODY')) {
escapeIdentifier = context.helper('escapeStyle');
}
// TODO Only escape the parts that need to be escaped if it is a compound expression with static
// text parts
argument = builder.functionCall(
escapeIdentifier,
[argument]);
} else {
argument = builder.functionCall(context.helper('str'), [ argument ]);
}
htmlArray.push(argument);
}
}
if (Array.isArray(argument)) {
argument.forEach(append);
} else {
append(argument);
}
if (htmlArray.length) {
return codegen.builder.html(htmlArray);
} else {
return null;
}
};
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| TextVDOM.js | 9.8% | (5 / 51) | 0% | (0 / 20) | 0% | (0 / 6) | 9.8% | (5 / 51) | |
| generateCode.js | 18.18% | (4 / 22) | 0% | (0 / 18) | 0% | (0 / 1) | 18.18% | (4 / 22) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | 1 1 1 1 1 | 'use strict';
const Node = require('../../Node');
const Literal = require('../../Literal');
const vdomUtil = require('../../../util/vdom');
class TextVDOM extends Node {
constructor(def) {
super('TextVDOM');
this.arguments = [def.argument];
this.isStatic = def.isStatic;
this.escape = def.escape !== false;
this.isHtmlOnly = true;
this.isChild = false;
this.createTextId = undefined;
this.strFuncId = undefined;
}
generateCode(codegen) {
var context = codegen.context;
vdomUtil.registerOptimizer(context);
return this;
}
_append(appendArgument) {
let args = this.arguments;
let len = args.length;
let last = args[len-1];
if (last instanceof Literal && appendArgument instanceof Literal) {
last.value += appendArgument.value;
} else {
args.push(appendArgument);
}
}
append(textVDOMToAppend) {
if (textVDOMToAppend.escape !== this.escape) {
return false;
}
if (!textVDOMToAppend.isStatic) {
this.isStatic = false;
}
if (textVDOMToAppend.strFuncId) {
this.strFuncId = textVDOMToAppend.strFuncId;
}
textVDOMToAppend.arguments.forEach(this._append, this);
return true;
}
writeCode(writer) {
let builder = writer.builder;
let args = this.arguments;
let escape = this.escape;
var funcName = escape ? 't' : 'h';
function writeTextArgs() {
writer.write('(');
for (let i=0, len=args.length; i<len; i++) {
let arg = args[i];
if (i !== 0) {
writer.write(' +\n');
writer.writeLineIndent();
writer.writeIndent();
}
writer.write(arg);
}
writer.write(')');
}
if (this.isChild) {
writer.write('.');
writer.write(builder.identifier(funcName));
} else if (this.isStatic && this.createTextId) {
writer.write(this.createTextId);
} else {
writer.write('out.');
writer.write(builder.identifier(funcName));
}
writeTextArgs();
}
}
module.exports = TextVDOM;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | 1 1 1 1 | 'use strict';
var TextVDOM = require('./TextVDOM');
var Literal = require('../../Literal');
var he = require('he'); // Used for dealing with HTML entities
module.exports = function(node, codegen, vdomUtil) {
var argument = codegen.generateCode(node.argument);
var escape = node.escape !== false;
var isStatic = null;
if (codegen.context.isFlagSet('SCRIPT_BODY')) {
escape = true;
}
if (argument instanceof Literal) {
var literalValue = argument.value;
if (literalValue == null || literalValue === '') {
// Don't add empty text nodes to the final tree
return null;
}
if (escape === false) {
escape = true;
if (typeof literalValue === 'string') {
if (literalValue.indexOf('<') !== -1) {
escape = false;
} else if (literalValue.indexOf('&') !== -1) {
argument = codegen.builder.literal(he.decode(literalValue));
}
}
}
}
isStatic = isStatic == null ? vdomUtil.isStaticValue(argument) : isStatic;
return new TextVDOM({ argument, isStatic, escape });
};
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 25.53% | (24 / 94) | 0% | (0 / 37) | 0% | (0 / 10) | 25.53% | (24 / 94) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var taglibLoader = require('../taglib-loader');
var nodePath = require('path');
var lassoPackageRoot = require('lasso-package-root');
var resolveFrom = require('resolve-from');
var scanTagsDir = require('../taglib-loader/scanTagsDir');
var DependencyChain = require('../taglib-loader/DependencyChain');
var lassoCachingFS = require('lasso-caching-fs');
var findCache = {};
var excludedDirs = {};
var excludedPackages = {};
var taglibsForNodeModulesDirCache = {};
/**
* Reset all internal state to the default state. This
* was added for testing purposes.
*/
function reset() {
lassoCachingFS.clearCaches();
findCache = {};
excludedDirs = {};
excludedPackages = {};
taglibsForNodeModulesDirCache = {};
}
function existsCached(path) {
return lassoCachingFS.existsSync(path);
}
function getModuleRootPackage(dirname) {
try {
return lassoPackageRoot.getRootPackage(dirname);
} catch(e) {
return undefined;
}
}
function getAllDependencyNames(pkg) {
var map = {};
if (pkg.dependencies) {
Object.keys(pkg.dependencies).forEach((name) => {
map[name] = true;
});
}
if (pkg.peerDependencies) {
Object.keys(pkg.peerDependencies).forEach((name) => {
map[name] = true;
});
}
if (pkg.devDependencies) {
Object.keys(pkg.devDependencies).forEach((name) => {
map[name] = true;
});
}
return Object.keys(map);
}
function find(dirname, registeredTaglibs) {
var found = findCache[dirname];
if (found) {
return found;
}
found = [];
var added = {};
var helper = {
alreadyAdded: function(taglibPath) {
return added.hasOwnProperty(taglibPath);
},
addTaglib: function(taglib) {
if (added[taglib.path]) {
return;
}
added[taglib.path] = true;
found.push(taglib);
},
foundTaglibPackages: {}
};
var rootDirname = process.cwd(); // Don't search up past this directory
var rootPkg = getModuleRootPackage(dirname);
if (rootPkg) {
rootDirname = rootPkg.__dirname; // Use the package's root directory as the top-level directory
}
// First walk up the directory tree looking for marko.json files or components/ directories
let curDirname = dirname;
while(true) {
if(!excludedDirs[curDirname]) {
let taglibPath = nodePath.join(curDirname, 'marko.json');
let taglib;
if (existsCached(taglibPath)) {
taglib = taglibLoader.loadTaglibFromFile(taglibPath);
helper.addTaglib(taglib);
}
if (!taglib || taglib.tagsDir === undefined) {
let componentsPath = nodePath.join(curDirname, 'components');
if (existsCached(componentsPath) && !excludedDirs[componentsPath] && !helper.alreadyAdded(componentsPath)) {
let taglib = taglibLoader.createTaglib(componentsPath);
scanTagsDir(componentsPath, nodePath.dirname(componentsPath), './components', taglib, new DependencyChain([componentsPath]));
helper.addTaglib(taglib);
}
}
}
if (curDirname === rootDirname) {
break;
}
let parentDirname = nodePath.dirname(curDirname);
if (!parentDirname || parentDirname === curDirname) {
break;
}
curDirname = parentDirname;
}
if (rootPkg) {
// Now look for `marko.json` from installed packages
getAllDependencyNames(rootPkg).forEach((name) => {
if (!excludedPackages[name]) {
let taglibPath = resolveFrom(rootPkg.__dirname, name + '/marko.json');
if (taglibPath) {
var taglib = taglibLoader.loadTaglibFromFile(taglibPath);
helper.addTaglib(taglib);
}
}
});
}
found = found.concat(registeredTaglibs);
findCache[dirname] = found;
return found;
}
function clearCache() {
lassoCachingFS.clearCaches();
findCache = {};
taglibsForNodeModulesDirCache = {};
}
function excludeDir(dir) {
excludedDirs[dir] = true;
}
function excludePackage(name) {
excludedPackages[name] = true;
}
exports.reset = reset;
exports.find = find;
exports.clearCache = clearCache;
exports.excludeDir = excludeDir;
exports.excludePackage = excludePackage;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| Attribute.js | 100% | (8 / 8) | 100% | (0 / 0) | 100% | (1 / 1) | 100% | (8 / 8) | |
| DependencyChain.js | 100% | (4 / 4) | 50% | (1 / 2) | 100% | (3 / 3) | 100% | (4 / 4) | |
| ImportedVariable.js | 33.33% | (1 / 3) | 100% | (0 / 0) | 0% | (0 / 1) | 33.33% | (1 / 3) | |
| NestedVariable.js | 50% | (1 / 2) | 100% | (0 / 0) | 0% | (0 / 1) | 50% | (1 / 2) | |
| Property.js | 25% | (1 / 4) | 100% | (0 / 0) | 0% | (0 / 1) | 25% | (1 / 4) | |
| Tag.js | 30% | (30 / 100) | 19.3% | (11 / 57) | 14.29% | (4 / 28) | 30% | (30 / 100) | |
| Taglib.js | 50.98% | (26 / 51) | 25% | (5 / 20) | 33.33% | (4 / 12) | 50.98% | (26 / 51) | |
| Transformer.js | 41.67% | (10 / 24) | 0% | (0 / 10) | 33.33% | (1 / 3) | 41.67% | (10 / 24) | |
| cache.js | 70% | (7 / 10) | 100% | (0 / 0) | 0% | (0 / 3) | 70% | (7 / 10) | |
| index.js | 76.19% | (16 / 21) | 0% | (0 / 2) | 40% | (2 / 5) | 76.19% | (16 / 21) | |
| json-file-reader.js | 44.44% | (4 / 9) | 100% | (0 / 0) | 0% | (0 / 1) | 44.44% | (4 / 9) | |
| loadAttributeFromProps.js | 89.66% | (52 / 58) | 70% | (7 / 10) | 90% | (18 / 20) | 89.66% | (52 / 58) | |
| loadAttributes.js | 100% | (9 / 9) | 100% | (0 / 0) | 100% | (1 / 1) | 100% | (9 / 9) | |
| loadTagFromFile.js | 46.67% | (7 / 15) | 0% | (0 / 2) | 0% | (0 / 1) | 46.67% | (7 / 15) | |
| loadTagFromProps.js | 57.83% | (133 / 230) | 44.12% | (45 / 102) | 63.41% | (26 / 41) | 57.83% | (133 / 230) | |
| loadTaglibFromFile.js | 46.67% | (7 / 15) | 0% | (0 / 2) | 0% | (0 / 1) | 46.67% | (7 / 15) | |
| loadTaglibFromProps.js | 50.99% | (77 / 151) | 18.18% | (8 / 44) | 62.5% | (10 / 16) | 50.99% | (77 / 151) | |
| loaders.js | 87.5% | (14 / 16) | 100% | (0 / 0) | 33.33% | (1 / 3) | 87.5% | (14 / 16) | |
| scanTagsDir.js | 15.38% | (16 / 104) | 0% | (0 / 47) | 0% | (0 / 6) | 16% | (16 / 100) | |
| tag-def-from-code.js | 12.12% | (4 / 33) | 0% | (0 / 14) | 0% | (0 / 1) | 12.12% | (4 / 33) | |
| types.js | 100% | (7 / 7) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (7 / 7) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 676 676 676 676 676 676 676 1 | 'use strict';
class Attribute {
constructor(name) {
this.name = name;
this.type = null;
this.required = false;
this.type = null;
this.allowExpressions = true;
this.setFlag = null;
this.pattern = null;
}
}
module.exports = Attribute;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 1119 1112 923 1 | 'use strict';
class DependencyChain {
constructor(array) {
this.array = array || [];
}
append(str) {
return new DependencyChain(this.array.concat(str));
}
toString() {
return '[' + this.array.join(' → ') + ']';
}
}
module.exports = DependencyChain;
|
| 1 2 3 4 5 6 7 8 9 10 11 | 1 | 'use strict';
class ImportedVariable {
constructor() {
this.targetProperty = null;
this.expression = null;
}
}
module.exports = ImportedVariable;
|
| 1 2 3 4 5 6 7 8 9 10 | 1 | 'use strict';
class NestedVariable {
constructor() {
this.name = null;
}
}
module.exports = NestedVariable;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 | 1 | 'use strict';
class Property {
constructor() {
this.name = null;
this.type = 'string';
this.value = undefined;
}
}
module.exports = Property;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | 1 1 1 1 1 1 1 238 238 238 238 238 238 498 498 3 495 176 176 173 3 3 495 1 1 1 17 17 17 1 | 'use strict';
var forEachEntry = require('raptor-util/forEachEntry');
var ok = require('assert').ok;
var CustomTag;
var path = require('path');
var markoModules = require('../modules');
function createCustomTag(el, tagDef) {
CustomTag = CustomTag || require('../ast/CustomTag');
return new CustomTag(el, tagDef);
}
function createCustomTagNodeFactory(tagDef) {
return function nodeFactory(el) {
return createCustomTag(el, tagDef);
};
}
class Tag{
constructor(filePath) {
this.filePath = filePath;
Eif (filePath) {
this.dir = path.dirname(filePath);
}
this.attributes = {};
this.transformers = {};
this.patternAttributes = [];
// NOTE: We don't set this properties since
// it breaks merging of tags when the same
// tag is declared at multiple levels
// this.taglibId = null;
// this.taglibPath = null;
// this.name = undefined;
// this.renderer = null;
// this.codeGeneratorModulePath = null;
// this.nodeFactoryPath = null;
// this.template = null;
// this.nestedVariables = null;
// this.importedVariables = null;
// this.bodyFunction = null;
// this.nestedTags = null;
// this.isRepeated = null;
// this.isNestedTag = false;
// this.parentTagName = null;
// this.openTagOnly = null;
// this.body = null;
// this.type = null; // Only applicable for nested tags
// this._nodeFactory = undefined;
}
forEachVariable(callback, thisObj) {
if (!this.nestedVariables) {
return;
}
this.nestedVariables.vars.forEach(callback, thisObj);
}
forEachImportedVariable(callback, thisObj) {
if (!this.importedVariables) {
return;
}
forEachEntry(this.importedVariables, function (key, importedVariable) {
callback.call(thisObj, importedVariable);
});
}
forEachTransformer(callback, thisObj) {
forEachEntry(this.transformers, function (key, transformer) {
callback.call(thisObj, transformer);
});
}
hasTransformers() {
/*jshint unused:false */
for (var k in this.transformers) {
if (this.transformers.hasOwnProperty(k)) {
return true;
}
}
return false;
}
addAttribute(attr) {
attr.filePath = this.filePath;
if (attr.pattern) {
this.patternAttributes.push(attr);
} else {
if (attr.name === '*') {
attr.dynamicAttribute = true;
if (attr.targetProperty === null || attr.targetProperty === '') {
attr.targetProperty = null;
}
else Eif (!attr.targetProperty) {
attr.targetProperty = '*';
}
}
this.attributes[attr.name] = attr;
}
}
toString() {
return '[Tag: <' + this.name + '@' + this.taglibId + '>]';
}
forEachAttribute(callback, thisObj) {
for (var attrName in this.attributes) {
if (this.attributes.hasOwnProperty(attrName)) {
callback.call(thisObj, this.attributes[attrName]);
}
}
}
getAttribute(attrName) {
var attributes = this.attributes;
// try by exact match first
var attribute = attributes[attrName] || attributes['*'];
if (attribute === undefined && this.patternAttributes) {
// try searching by pattern
for (var i = 0, len = this.patternAttributes.length; i < len; i++) {
var patternAttribute = this.patternAttributes[i];
if (patternAttribute.pattern.test(attrName)) {
attribute = patternAttribute;
break;
}
}
}
return attribute;
}
hasAttribute(attrName) {
return this.attributes.hasOwnProperty(attrName);
}
addNestedVariable(nestedVariable) {
Eif (!this.nestedVariables) {
this.nestedVariables = {
__noMerge: true,
vars: []
};
}
this.nestedVariables.vars.push(nestedVariable);
}
addImportedVariable(importedVariable) {
if (!this.importedVariables) {
this.importedVariables = {};
}
var key = importedVariable.targetProperty;
this.importedVariables[key] = importedVariable;
}
addTransformer(transformer) {
var key = transformer.path;
transformer.taglibId = this.taglibId;
this.transformers[key] = transformer;
}
setBodyFunction(name, params) {
this.bodyFunction = {
__noMerge: true,
name: name,
params: params
};
}
setBodyProperty(propertyName) {
this.bodyProperty = propertyName;
}
addNestedTag(nestedTag) {
ok(nestedTag.name, '"nestedTag.name" is required');
if (!this.nestedTags) {
this.nestedTags = {};
}
nestedTag.isNestedTag = true;
if (!nestedTag.targetProperty) {
nestedTag.targetProperty = nestedTag.name;
}
this.nestedTags[nestedTag.name] = nestedTag;
}
forEachNestedTag(callback, thisObj) {
if (!this.nestedTags) {
return;
}
forEachEntry(this.nestedTags, function (key, nestedTag) {
callback.call(thisObj, nestedTag);
});
}
hasNestedTags() {
return this.nestedTags != null;
}
getNodeFactory() {
var nodeFactory = this._nodeFactory;
if (nodeFactory !== undefined) {
return nodeFactory;
}
let codeGeneratorModulePath = this.codeGeneratorModulePath;
if (this.codeGeneratorModulePath) {
var loadedCodeGenerator = markoModules.require(this.codeGeneratorModulePath);
nodeFactory = function(elNode) {
elNode.setType(codeGeneratorModulePath);
elNode.setCodeGenerator(loadedCodeGenerator);
return elNode;
};
} else if (this.nodeFactoryPath) {
nodeFactory = markoModules.require(this.nodeFactoryPath);
if (typeof nodeFactory !== 'function') {
throw new Error('Invalid node factory exported by module at path "' + this.nodeFactoryPath + '"');
}
} else if (this.renderer || this.template || this.isNestedTag) {
nodeFactory = createCustomTagNodeFactory(this);
} else {
return null;
}
return (this._nodeFactory = nodeFactory);
}
toJSON() {
return this;
}
setTaglib(taglib) {
this.taglibId = taglib ? taglib.id : null;
this.taglibPath = taglib ? taglib.path : null;
}
}
module.exports = Tag;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | 1 1 1 1 1 7 7 7 7 7 7 7 7 7 7 7 108 108 108 108 238 238 238 238 1 1 | 'use strict';
var forEachEntry = require('raptor-util/forEachEntry');
var ok = require('assert').ok;
var path = require('path');
var loaders = require('./loaders');
function handleImport(taglib, importedTaglib) {
var importsLookup = taglib.importsLookup || (taglib.importsLookup = {});
if (importsLookup.hasOwnProperty(importedTaglib.path)) {
return;
}
importsLookup[importedTaglib.path] = importedTaglib;
if (!taglib.imports) {
taglib.imports = [];
}
taglib.imports.push(importedTaglib);
if (importedTaglib.imports) {
importedTaglib.imports.forEach(function(nestedImportedTaglib) {
handleImport(taglib, nestedImportedTaglib);
});
}
}
class Taglib {
constructor(filePath) {
ok(filePath, '"filePath" expected');
this.filePath = this.path /* deprecated */ = this.id = filePath;
this.dirname = path.dirname(this.filePath);
this.tags = {};
this.textTransformers = [];
this.transformers = [];
this.attributes = {};
this.patternAttributes = [];
this.inputFilesLookup = {};
this.imports = null;
this.importsLookup = null;
}
addAttribute(attribute) {
ok(attribute.key, '"key" is required for global attributes');
attribute.filePath = this.filePath;
Iif (!attribute.pattern && !attribute.name) {
throw new Error('Invalid attribute: ' + require('util').inspect(attribute));
}
this.attributes[attribute.key] = attribute;
}
getAttribute(name) {
var attribute = this.attributes[name];
if (!attribute) {
for (var i = 0, len = this.patternAttributes.length; i < len; i++) {
var patternAttribute = this.patternAttributes[i];
if (patternAttribute.pattern.test(name)) {
attribute = patternAttribute;
}
}
}
return attribute;
}
addTag(tag) {
ok(arguments.length === 1, 'Invalid args');
Iif (!tag.name) {
throw new Error('"tag.name" is required: ' + JSON.stringify(tag));
}
this.tags[tag.name] = tag;
tag.taglibId = this.id || this.path;
}
addTextTransformer(transformer) {
this.textTransformers.push(transformer);
}
addTransformer(transformer) {
this.transformers.push(transformer);
}
forEachTag(callback, thisObj) {
forEachEntry(this.tags, function (key, tag) {
callback.call(thisObj, tag);
}, this);
}
addImport(path) {
var importedTaglib = loaders.loadTaglibFromFile(path);
handleImport(this, importedTaglib);
}
toJSON() {
return {
path: this.path,
tags: this.tags,
textTransformers: this.textTransformers,
attributes: this.attributes,
patternAttributes: this.patternAttributes,
imports: this.imports
};
}
}
module.exports = Taglib;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 1 1 18 18 18 18 18 18 18 1 | 'use strict';
var nextTransformerId = 0;
var markoModules = require('../modules');
class Transformer {
constructor() {
this.id = nextTransformerId++;
this.name = null;
this.tag = null;
this.path = null;
this.priority = null;
this._func = null;
this.properties = {};
}
getFunc() {
if (!this.path) {
throw new Error('Transformer path not defined for tag transformer (tag=' + this.tag + ')');
}
if (!this._func) {
var transformer = markoModules.require(this.path);
if (typeof transformer === 'function') {
if (transformer.prototype.process) {
var Clazz = transformer;
var instance = new Clazz();
instance.id = this.id;
this._func = instance.process.bind(instance);
} else {
this._func = transformer;
}
} else {
this._func = transformer.process || transformer.transform;
}
}
return this._func;
}
toString() {
return '[Taglib.Transformer: ' + this.path + ']';
}
}
module.exports = Transformer;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 1 1 1 1 1 1 1 | var cache = {};
function get(key) {
return cache[key];
}
function put(key, value) {
cache[key] = value;
}
function clear() {
cache = {};
}
exports.get = get;
exports.put = put;
exports.clear = clear;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 1 1 1 1 1 7 1 1 1 7 1 1 1 1 1 1 | var cache = require('./cache');
var types = require('./types');
var loaders = require('./loaders');
var DependencyChain = require('./DependencyChain');
function loadTaglibFromProps(taglib, taglibProps) {
return loaders.loadTaglibFromProps(taglib, taglibProps);
}
function loadTaglibFromFile(filePath) {
return loaders.loadTaglibFromFile(filePath);
}
function clearCache() {
cache.clear();
}
function createTaglib(filePath) {
return new types.Taglib(filePath);
}
function loadTag(tagProps, filePath) {
var tag = new types.Tag(filePath);
loaders.loadTagFromProps(tag, tagProps, new DependencyChain(filePath ? [filePath] : []));
return tag;
}
exports.clearCache = clearCache;
exports.createTaglib = createTaglib;
exports.loadTaglibFromProps = loadTaglibFromProps;
exports.loadTaglibFromFile = loadTaglibFromFile;
exports.loadTag = loadTag;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 1 1 1 1 | var fs = require('fs');
var stripJsonComments = require('strip-json-comments');
var fsReadOptions = { encoding: 'utf8' };
exports.readFileSync = function (path) {
var json = fs.readFileSync(path, fsReadOptions);
try {
var taglibProps = JSON.parse(stripJsonComments(json));
return taglibProps;
} catch(e) {
throw new Error('Unable to parse JSON file at path "' + path + '". Error: ' + e);
}
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | 1 1 1 1 1 676 676 676 676 676 676 676 1 675 676 520 520 258 262 174 174 3 3 3 3 2 2 196 196 1 1 2 2 1 1 1 28 28 13 108 177 1 676 676 676 676 676 676 676 1 106 1 | 'use strict';
var assert = require('assert');
var raptorRegexp = require('raptor-regexp');
var propertyHandlers = require('property-handlers');
var types = require('./types');
var createError = require('raptor-util/createError');
class AttrLoader {
constructor(attr, dependencyChain) {
assert.ok(attr, '"attr" is required');
assert.ok(dependencyChain, '"dependencyChain" is required');
this.attr = attr;
this.dependencyChain = dependencyChain;
}
load(attrProps) {
assert.ok(arguments.length === 1);
Iif (attrProps == null) {
attrProps = {};
} else if (typeof attrProps === 'string') {
attrProps = {
type: attrProps
};
} else {
assert.ok(typeof attrProps === 'object', 'Invalid "attrProps"');
}
propertyHandlers(attrProps, this, this.dependencyChain.toString());
}
/**
* The attribute type. One of the following:
* - string (the default)
* - expression (a JavaScript expression)
* - number
* - integer
* - int
* - boolean
* - float
* - double
* - object
* - array
*
*/
type(value) {
var attr = this.attr;
if (value.charAt(0) === '#') {
attr.ref = value.substring(1);
} else {
attr.type = value;
}
}
/**
* The name of the target property to use when mapping
* the attribute to a property on the target object.
*/
targetProperty(value) {
var attr = this.attr;
attr.targetProperty = value;
}
/**
* The "default-value" property allows a default value
* to be provided when the attribute is not declared
* on the custom tag.
*/
defaultValue(value) {
var attr = this.attr;
attr.defaultValue = value;
}
/**
* The "pattern" property allows the attribute
* to be matched based on a simplified regular expression.
*
* Example:
*
* "pattern": "myprefix-*"
*/
pattern(value) {
var attr = this.attr;
Eif (value === true) {
var patternRegExp = raptorRegexp.simple(attr.name);
attr.pattern = patternRegExp;
}
}
/**
* If "allow-expressions" is set to true (the default) then
* the the attribute value will be parsed to find any dynamic
* parts.
*/
allowExpressions(value) {
var attr = this.attr;
attr.allowExpressions = value;
}
/**
* By default, the Marko compiler maps an attribute
* to a property by removing all dashes from the attribute
* name and converting each character after a dash to
* an uppercase character (e.g. "my-attr" --> "myAttr").
*
* Setting "preserve-name" to true will prevent this from
* happening for the attribute.
*/
preserveName(value) {
var attr = this.attr;
attr.preserveName = value;
}
/**
* Declares an attribute as required. Currently, this is
* not enforced and is only used for documentation purposes.
*
* Example:
* "required": true
*/
required(value) {
var attr = this.attr;
attr.required = value === true;
}
/**
* This is the opposite of "preserve-name" and will result
* in dashes being removed from the attribute if set to true.
*/
removeDashes(value) {
var attr = this.attr;
attr.removeDashes = value === true;
}
/**
* The description of the attribute. Only used for documentation.
*/
description() {
}
/**
* The "set-flag" property allows a "flag" to be added to a Node instance
* at compile time if the attribute is found on the node. This is helpful
* if an attribute uses a pattern and a transformer wants to have a simple
* check to see if the Node has an attribute that matched the pattern.
*
* Example:
*
* "set-flag": "myCustomFlag"
*
* A Node instance can be checked if it has a flag set as shown below:
*
* if (node.hasFlag('myCustomFlag')) { ... }
*
*
*/
setFlag(value) {
var attr = this.attr;
attr.setFlag = value;
}
/**
* An attribute can be marked for ignore. Ignored attributes
* will be ignored during compilation.
*/
ignore(value) {
var attr = this.attr;
Eif (value === true) {
attr.ignore = true;
}
}
autocomplete(value) {
this.attr.autocomplete = value;
}
enum(value) {
this.attr.enum = value;
}
deprecated(value) {
this.attr.deprecated = value;
}
name(value) {
this.attr.name = value;
}
html(value) {
this.attr.html = value === true;
}
}
function loadAttributeFromProps(attrName, attrProps, dependencyChain) {
assert.ok(typeof attrName === 'string');
assert.ok(dependencyChain, '"dependencyChain" is required');
var attr = new types.Attribute(attrName);
var attrLoader = new AttrLoader(attr, dependencyChain);
try {
attrLoader.load(attrProps);
} catch(err) {
throw createError('Unable to load attribute "' + attrName + '" (' + dependencyChain + '): ' + err, err);
}
return attr;
}
loadAttributeFromProps.isSupportedProperty = function(name) {
return AttrLoader.prototype.hasOwnProperty(name);
};
module.exports = loadAttributeFromProps;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 1 1 1 1 177 177 177 173 173 | var ok = require('assert').ok;
var forEachEntry = require('raptor-util/forEachEntry');
var loaders = require('./loaders');
module.exports = function loadAttributes(value, parent, dependencyChain) {
ok(parent);
ok(dependencyChain);
forEachEntry(value, (attrName, attrProps) => {
var attr = loaders.loadAttributeFromProps(
attrName,
attrProps,
dependencyChain.append('@' + attrName));
parent.addAttribute(attr);
});
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 1 1 1 1 1 1 1 | var jsonFileReader = require('./json-file-reader');
var types = require('./types');
var cache = require('./cache');
var loaders = require('./loaders');
var ok = require('assert').ok;
function loadTagFromFile(filePath) {
ok(filePath, '"filePath" is required');
var tag = cache.get(filePath);
// Only load a tag once by caching the loaded tags using the file
// system file path as the key
if (!tag) {
tag = new types.Tag(filePath);
cache.put(filePath, tag);
var tagProps = jsonFileReader.readFileSync(filePath);
loaders.loadTagFromProps(tag, tagProps);
}
return tag;
}
module.exports = loadTagFromFile;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 106 29 1 238 4 234 425 61 173 238 238 238 238 238 173 238 1 1 1 1 1 1 1 1 325 325 325 325 325 325 325 325 325 325 325 325 325 325 325 325 325 325 37 106 106 106 106 70 70 70 36 36 36 36 37 37 37 288 288 288 288 325 325 325 325 325 325 8 8 8 8 177 177 13 13 13 13 6 6 6 6 5 5 17 17 17 17 11 17 17 17 6 17 17 1 1 1 1 64 2 10 121 121 121 195 77 1 142 1 238 238 238 238 238 238 1 1 | 'use strict';
var ok = require('assert').ok;
var propertyHandlers = require('property-handlers');
var isObjectEmpty = require('raptor-util/isObjectEmpty');
var nodePath = require('path');
var markoModules = require('../modules'); // NOTE: different implementation for browser
var ok = require('assert').ok;
var bodyFunctionRegExp = /^([A-Za-z_$][A-Za-z0-9_]*)(?:\(([^)]*)\))?$/;
var safeVarName = /^[A-Za-z_$][A-Za-z0-9_]*$/;
var propertyHandlers = require('property-handlers');
var forEachEntry = require('raptor-util/forEachEntry');
var markoCompiler = require('../');
var createError = require('raptor-util/createError');
var types = require('./types');
var loaders = require('./loaders');
function exists(path) {
try {
markoModules.resolve(path);
return true;
} catch(e) {
return false;
}
}
function removeDashes(str) {
return str.replace(/-([a-z])/g, function (match, lower) {
return lower.toUpperCase();
});
}
function hasAttributes(tagProps) {
if (tagProps.attributes != null) {
return true;
}
for (var name in tagProps) {
if (tagProps.hasOwnProperty(name) && name.startsWith('@')) {
return true;
}
}
return false;
}
/**
* We load tag definition using this class. Properties in the taglib
* definition (which is just a JavaScript object with properties)
* are mapped to handler methods in an instance of this type.
*
* @param {Tag} tag The initially empty Tag instance that we populate
* @param {String} dirname The full file system path associated with the tag being loaded
* @param {String} path An informational path associated with this tag (used for error reporting)
*/
class TagLoader {
constructor(tag, dependencyChain) {
this.tag = tag;
this.dependencyChain = dependencyChain;
this.filePath = tag.filePath;
this.dirname = tag.dir || tag.dirname;
}
load(tagProps) {
if (!hasAttributes(tagProps)) {
// allow any attributes if no attributes are declared
tagProps.attributes = {
'*': {
type: 'string',
targetProperty: null,
preserveName: false
}
};
}
propertyHandlers(tagProps, this, this.dependencyChain.toString());
}
_handleVar(value, dependencyChain) {
var tag = this.tag;
var nestedVariable;
Iif (typeof value === 'string') {
nestedVariable = {
name: value
};
} else {
nestedVariable = {};
propertyHandlers(value, {
name: function(value) {
nestedVariable.name = value;
},
nameFromAttribute: function(value) {
nestedVariable.nameFromAttribute = value;
}
}, dependencyChain.toString());
Iif (!nestedVariable.name && !nestedVariable.nameFromAttribute) {
throw new Error('The "name" or "name-from-attribute" attribute is required for a nested variable (' + dependencyChain + ')');
}
}
tag.addNestedVariable(nestedVariable);
}
/**
* This is handler is for any properties that didn't match
* one of the default property handlers. This is used to
* match properties in the form of "@attr_name" or
* "<nested_tag_name>"
*/
'*'(name, value) {
var tag = this.tag;
var dependencyChain = this.dependencyChain;
var parts = name.split(/\s+|\s+[,]\s+/);
var i;
var part;
var hasNestedTag = false;
var hasAttr = false;
var nestedTagTargetProperty = null;
// We do one pass to figure out if there is an
// attribute or nested tag or both
for (i=0; i<parts.length; i++) {
part = parts[i];
Eif (part.startsWith('@')) {
hasAttr = true;
Eif (i === 0) {
// Use the first attribute value as the name of the target property
nestedTagTargetProperty = part.substring(1);
}
} else if (part.startsWith('<')) {
hasNestedTag = true;
} else {
// Unmatched property that is not an attribute or a
// nested tag
return false;
}
}
var attrProps = {};
var tagProps = {};
var k;
if (value != null && typeof value === 'object') {
for (k in value) {
Eif (value.hasOwnProperty(k)) {
Iif (k.startsWith('@') || k.startsWith('<')) {
// Move over all of the attributes and nested tags
// to the tag definition.
tagProps[k] = value[k];
delete value[k];
} else {
// The property is not a shorthand attribute or shorthand
// tag so move it over to either the tag definition
// or the attribute definition or both the tag definition
// and attribute definition.
var propNameDashes = removeDashes(k);
if (isSupportedProperty(propNameDashes) &&
loaders.isSupportedAttributeProperty(propNameDashes)) {
// Move over all of the properties that are associated with a tag
// and attribute
tagProps[k] = value[k];
attrProps[k] = value[k];
delete value[k];
} else Iif (isSupportedProperty(propNameDashes)) {
// Move over all of the properties that are associated with a tag
tagProps[k] = value[k];
delete value[k];
} else Eif (loaders.isSupportedAttributeProperty(propNameDashes)) {
// Move over all of the properties that are associated with an attr
attrProps[k] = value[k];
delete value[k];
}
}
}
}
// If there are any left over properties then something is wrong
// with the user's taglib.
Iif (!isObjectEmpty(value)) {
throw new Error('Unsupported properties of [' +
Object.keys(value).join(', ') +
']');
}
var type = attrProps.type;
Iif (!type && hasAttr && hasNestedTag) {
// If we have an attribute and a nested tag then default
// the attribute type to "expression"
attrProps.type = 'expression';
}
} else Eif (typeof value === 'string') {
Iif (hasNestedTag && hasAttr) {
tagProps = attrProps = {
type: value
};
} else Iif (hasNestedTag) {
tagProps = {
type: value
};
} else {
attrProps = {
type: value
};
}
}
// Now that we have separated out attribute properties and tag properties
// we need to create the actual attributes and nested tags
for (i=0; i<parts.length; i++) {
part = parts[i];
Eif (part.startsWith('@')) {
// This is a shorthand attribute
var attrName = part.substring(1);
var attr = loaders.loadAttributeFromProps(
attrName,
attrProps,
dependencyChain.append(part));
tag.addAttribute(attr);
} else if (part.startsWith('<')) {
// This is a shorthand nested tag
let nestedTag = new types.Tag(this.filePath);
loadTagFromProps(
nestedTag,
tagProps,
dependencyChain.append(part));
// We use the '[]' suffix to indicate that a nested tag
// can be repeated
var isNestedTagRepeated = false;
if (part.endsWith('[]')) {
isNestedTagRepeated = true;
part = part.slice(0, -2);
}
var nestedTagName = part.substring(1, part.length-1);
nestedTag.name = nestedTagName;
nestedTag.isRepeated = isNestedTagRepeated;
// Use the name of the attribute as the target property unless
// this target property was explicitly provided
nestedTag.targetProperty = attrProps.targetProperty || nestedTagTargetProperty;
tag.addNestedTag(nestedTag);
if (!nestedTag.isRepeated) {
let attr = loaders.loadAttributeFromProps(
nestedTag.targetProperty,
{ type: 'object' },
dependencyChain.append(part));
tag.addAttribute(attr);
}
} else {
return false;
}
}
}
/**
* The tag name
* @param {String} value The tag name
*/
name(value) {
var tag = this.tag;
tag.name = value;
}
/**
* The path to the renderer JS module to use for this tag.
*
* NOTE: We use the equivalent of require.resolve to resolve the JS module
* and use the tag directory as the "from".
*
* @param {String} value The renderer path
*/
renderer(value) {
var tag = this.tag;
var dirname = this.dirname;
var path = markoModules.resolveFrom(dirname, value);
tag.renderer = path;
}
/**
* A tag can use a renderer or a template to do the rendering. If
* a template is provided then the value should be the path to the
* template to use to render the custom tag.
*/
template(value) {
var tag = this.tag;
var dirname = this.dirname;
var path = nodePath.resolve(dirname, value);
if (!exists(path)) {
throw new Error('Template at path "' + path + '" does not exist.');
}
tag.template = path;
}
/**
* An Object where each property maps to an attribute definition.
* The property key will be the attribute name and the property value
* will be the attribute definition. Example:
* {
* "attributes": {
* "foo": "string",
* "bar": "expression"
* }
* }
*/
attributes(value) {
var tag = this.tag;
loaders.loadAttributes(value, tag, this.dependencyChain.append('attributes'));
}
/**
* A custom tag can be mapped to module that is is used
* to generate compile-time code for the custom tag. A
* node type is created based on the methods and methods
* exported by the code codegen module.
*/
codeGenerator(value) {
var tag = this.tag;
var dirname = this.dirname;
var path = markoModules.resolveFrom(dirname, value);
tag.codeGeneratorModulePath = path;
}
/**
* A custom tag can be mapped to a compile-time Node that gets
* added to the parsed Abstract Syntax Tree (AST). The Node can
* then generate custom JS code at compile time. The value
* should be a path to a JS module that gets resolved using the
* equivalent of require.resolve(path)
*/
nodeFactory(value) {
var tag = this.tag;
var dirname = this.dirname;
var path = markoModules.resolveFrom(dirname, value);
tag.nodeFactoryPath = path;
}
/**
* If the "preserve-whitespace" property is set to true then
* all whitespace nested below the custom tag in a template
* will be stripped instead of going through the normal whitespace
* removal rules.
*/
preserveWhitespace(value) {
var tag = this.tag;
tag.preserveWhitespace = !!value;
}
/**
* If a custom tag has an associated transformer then the transformer
* will be called on the compile-time Node. The transformer can manipulate
* the AST using the DOM-like API to change how the code gets generated.
*/
transformer(value) {
var tag = this.tag;
var dirname = this.dirname;
var transformer = new types.Transformer();
if (typeof value === 'string') {
// The value is a simple string type
// so treat the value as the path to the JS
// module for the transformer
value = {
path: value
};
}
/**
* The transformer is a complex type and we need
* to process each property to load the Transformer
* definition.
*/
propertyHandlers(value, {
path(value) {
var path = markoModules.resolveFrom(dirname, value);
transformer.path = path;
},
priority(value) {
transformer.priority = value;
},
name(value) {
transformer.name = value;
},
properties(value) {
var properties = transformer.properties || (transformer.properties = {});
for (var k in value) {
if (value.hasOwnProperty(k)) {
properties[k] = value[k];
}
}
}
}, this.dependencyChain.append('transformer'));
ok(transformer.path, '"path" is required for transformer');
tag.addTransformer(transformer);
}
/**
* The "var" property is used to declared nested variables that get
* added as JavaScript variables at compile time.
*
* Examples:
*
* "var": "myScopedVariable",
*
* "var": {
* "name": "myScopedVariable"
* }
*
* "var": {
* "name-from-attribute": "var"
* }
*/
var(value) {
this._handleVar(value, this.dependencyChain.append('var'));
}
/**
* The "vars" property is equivalent to the "var" property
* except that it expects an array of nested variables.
*/
vars(value) {
Eif (value) {
value.forEach((v, i) => {
this._handleVar(v, this.dependencyChain.append('vars[' + i + ']'));
});
}
}
/**
* The "body-function" property" allows the nested body content to be mapped
* to a function at compile time. The body function gets mapped to a property
* of the tag renderer at render time. The body function can have any number
* of parameters.
*
* Example:
* - "body-function": "_handleBody(param1, param2, param3)"
*/
bodyFunction(value) {
var tag = this.tag;
var parts = bodyFunctionRegExp.exec(value);
if (!parts) {
throw new Error('Invalid value of "' + value + '" for "body-function". Expected value to be of the following form: <function-name>([param1, param2, ...])');
}
var functionName = parts[1];
var params = parts[2];
if (params) {
params = params.trim().split(/\s*,\s*/);
for (var i=0; i<params.length; i++) {
if (params[i].length === 0) {
throw new Error('Invalid parameters for body-function with value of "' + value + '"');
} else if (!safeVarName.test(params[i])) {
throw new Error('Invalid parameter name of "' + params[i] + '" for body-function with value of "' + value + '"');
}
}
} else {
params = [];
}
tag.setBodyFunction(functionName, params);
}
/**
* The "import-var" property can be used to add a property to the
* input object of the tag renderer whose value is determined by
* a JavaScript expression.
*
* Example:
* "import-var": {
* "myTargetProperty": "data.myCompileTimeJavaScriptExpression",
* }
*/
importVar(value) {
var tag = this.tag;
forEachEntry(value, (varName, varValue) => {
var importedVar = {
targetProperty: varName
};
var expression = varValue;
if (!expression) {
expression = varName;
}
else if (typeof expression === 'object') {
expression = expression.expression;
}
if (!expression) {
throw new Error('Invalid "import-var": ' + require('util').inspect(varValue));
}
importedVar.expression = markoCompiler.builder.parseExpression(expression);
tag.addImportedVariable(importedVar);
});
}
/**
* The tag type.
*/
type(value) {
var tag = this.tag;
tag.type = value;
}
/**
* Declare a nested tag.
*
* Example:
* {
* ...
* "nested-tags": {
* "tab": {
* "target-property": "tabs",
* "isRepeated": true
* }
* }
* }
*/
nestedTags(value) {
var filePath = this.filePath;
var tag = this.tag;
forEachEntry(value, (nestedTagName, nestedTagDef) => {
var dependencyChain = this.dependencyChain.append(`nestedTags["${nestedTagName}]`);
var nestedTag = new types.Tag(filePath);
loadTagFromProps(
nestedTag,
nestedTagDef,
dependencyChain);
nestedTag.name = nestedTagName;
tag.addNestedTag(nestedTag);
if (!nestedTag.isRepeated) {
let attr = loaders.loadAttributeFromProps(
nestedTag.targetProperty,
{ type: 'object' },
dependencyChain);
tag.addAttribute(attr);
}
});
}
escapeXmlBody(value) {
if (value === false) {
this.tag.escapeXmlBody = false;
}
}
/**
* Sends the body content type. This is used to control how the body
* content is parsed.
*/
body(value) {
if (value === 'static-text' || value === 'parsed-text' || value === 'html') {
this.tag.body = value;
} else {
throw new Error('Invalid value for "body". Allowed: "static-text", "parsed-text" or "html"');
}
}
openTagOnly(value) {
this.tag.openTagOnly = value;
}
noOutput(value) {
this.tag.noOutput = value;
}
autocomplete(value) {
this.tag.autocomplete = value;
}
parseOptions(value) {
this.tag.parseOptions = value;
}
deprecated(value) {
this.tag.deprecated = value;
}
parseAttributes(value) {
this.tag.parseAttributes = value;
}
attributeGroups(value) {
Iif (!value) {
return;
}
var attributeGroups = this.tag.attributeGroups || (this.tag.attributeGroups = []);
this.tag.attributeGroups = attributeGroups.concat(value);
}
html(value) {
this.tag.html = value === true;
}
htmlType(value) {
this.tag.htmlType = value;
}
}
function isSupportedProperty(name) {
return TagLoader.prototype.hasOwnProperty(name);
}
function loadTagFromProps(tag, tagProps, dependencyChain) {
ok(typeof tagProps === 'object', 'Invalid "tagProps"');
ok(dependencyChain, '"dependencyChain" is required');
var tagLoader = new TagLoader(tag, dependencyChain);
try {
tagLoader.load(tagProps);
} catch(err) {
throw createError('Unable to load tag (' + dependencyChain + '): ' + err, err);
}
return tag;
}
module.exports = loadTagFromProps;
loadTagFromProps.isSupportedProperty = isSupportedProperty;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 1 1 1 1 1 1 1 | var jsonFileReader = require('./json-file-reader');
var types = require('./types');
var cache = require('./cache');
var loaders = require('./loaders');
var ok = require('assert').ok;
function loadFromFile(filePath) {
ok(filePath, '"filePath" is required');
var taglib = cache.get(filePath);
// Only load a taglib once by caching the loaded taglibs using the file
// system file path as the key
if (!taglib) {
taglib = new types.Taglib(filePath);
cache.put(filePath, taglib);
var taglibProps = jsonFileReader.readFileSync(filePath);
loaders.loadTaglibFromProps(taglib, taglibProps);
}
return taglib;
}
module.exports = loadFromFile;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 7 7 7 7 7 7 7 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 1 1 108 108 108 108 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 70 70 70 1 7 7 7 7 7 7 7 7 7 1 | 'use strict';
var ok = require('assert').ok;
var types = require('./types');
var nodePath = require('path');
var scanTagsDir = require('./scanTagsDir');
var markoModules = require('../modules'); // NOTE: different implementation for browser
var propertyHandlers = require('property-handlers');
var types = require('./types');
var jsonFileReader = require('./json-file-reader');
var tryRequire = require('try-require');
var resolveFrom = tryRequire('resolve-from', require);
var DependencyChain = require('./DependencyChain');
var createError = require('raptor-util/createError');
var loaders = require('./loaders');
function exists(path) {
try {
markoModules.resolve(path);
return true;
} catch(e) {
return false;
}
}
/**
* We load a taglib definion using this class. Properties in the taglib
* definition (which is just a JavaScript object with properties)
* are mapped to handler methods in an instance of this type.
*
*
* @param {Taglib} taglib The initially empty Taglib instance that we will populate
* @param {String} path The file system path to the taglib that we are loading
*/
class TaglibLoader {
constructor(taglib, dependencyChain) {
ok(dependencyChain instanceof DependencyChain, '"dependencyChain" is not valid');
this.dependencyChain = dependencyChain;
this.taglib = taglib;
this.filePath = taglib.filePath;
this.dirname = taglib.dirname;
}
load(taglibProps) {
var taglib = this.taglib;
propertyHandlers(taglibProps, this, this.dependencyChain.toString());
Iif (!taglib.id) {
// Fixes #73
// See if there is a package.json in the same directory as the taglib file.
// If so, and if that package.json file has a "name" property then we will
// use the the name as the "taglib ID". The taglib ID is used to uniquely
// identity a taglib (ignoring version) and it is used to prevent the same
// taglib from being loaded multiple times.
//
// Using the file path as the taglib ID doesn't work so well since we might find
// the same taglib multiple times in the Node.js module search path with
// different paths.
var filePath = this.filePath;
var dirname = this.dirname;
var packageJsonPath = nodePath.join(dirname, 'package.json');
try {
var pkg = jsonFileReader.readFileSync(packageJsonPath);
taglib.id = pkg.name;
} catch(e) {}
if (!taglib.id) {
taglib.id = filePath;
}
}
}
_handleTag(tagName, value, dependencyChain) {
var tagProps;
var tagFilePath = this.filePath;
var tag;
Iif (typeof value === 'string') {
tagFilePath = nodePath.resolve(this.dirname, value);
if (!exists(tagFilePath)) {
throw new Error('Tag at path "' + tagFilePath + '" does not exist. (' + dependencyChain + ')');
}
tag = new types.Tag(tagFilePath);
tagProps = jsonFileReader.readFileSync(tagFilePath);
dependencyChain = dependencyChain.append(tagFilePath);
} else {
tag = new types.Tag(this.filePath);
tagProps = value;
}
loaders.loadTagFromProps(tag, tagProps, dependencyChain);
Eif (tag.name === undefined) {
tag.name = tagName;
}
this.taglib.addTag(tag);
}
// We register a wildcard handler to handle "@my-attr" and "<my-tag>"
// properties (shorthand syntax)
'*'(name, value) {
var taglib = this.taglib;
var filePath = this.filePath;
Eif (name.startsWith('<')) {
let tagName = name.slice(1, -1);
this._handleTag(tagName, value, this.dependencyChain.append(name));
} else if (name.startsWith('@')) {
var attrKey = name.substring(1);
var attr = loaders.loadAttributeFromProps(
attrKey,
value,
this.dependencyChain.append('@' + attrKey));
attr.filePath = filePath;
attr.key = attrKey;
taglib.addAttribute(attr);
} else {
return false;
}
}
attributes(value) {
// The value of the "attributes" property will be an object
// where each property maps to an attribute definition. Since these
// attributes are on the taglib they will be "global" attribute
// defintions.
//
// The property key will be the attribute name and the property value
// will be the attribute definition. Example:
// {
// "attributes": {
// "foo": "string",
// "bar": "expression"
// }
// }
var taglib = this.taglib;
Object.keys(value).forEach((attrName) => {
var attrDef = value[attrName];
var attr = loaders.loadAttributeFromProps(
attrName,
attrDef,
this.dependencyChain.append('@' + attrName));
attr.key = attrName;
taglib.addAttribute(attr);
});
}
tags(tags) {
// The value of the "tags" property will be an object
// where each property maps to an attribute definition. The property
// key will be the tag name and the property value
// will be the tag definition. Example:
// {
// "tags": {
// "foo": {
// "attributes": { ... }
// },
// "bar": {
// "attributes": { ... }
// },
// }
// }
for (var tagName in tags) {
if (tags.hasOwnProperty(tagName)) {
this._handleTag(tagName, tags[tagName], this.dependencyChain.append('tags.' + tagName));
}
}
}
tagsDir(dir) {
// The "tags-dir" property is used to supporting scanning
// of a directory to discover custom tags. Scanning a directory
// is a much simpler way for a developer to create custom tags.
// Only one tag is allowed per directory and the directory name
// corresponds to the tag name. We only search for directories
// one level deep.
var taglib = this.taglib;
var path = this.filePath;
var dirname = this.dirname;
taglib.tagsDir = dir;
if (dir != null) {
if (Array.isArray(dir)) {
for (var i = 0; i < dir.length; i++) {
scanTagsDir(path, dirname, dir[i], taglib, this.dependencyChain.append(`tags-dir[${i}]`));
}
} else {
scanTagsDir(path, dirname, dir, taglib, this.dependencyChain.append(`tags-dir`));
}
}
}
taglibImports(imports) {
if (!resolveFrom) {
return;
}
// The "taglib-imports" property allows another taglib to be imported
// into this taglib so that the tags defined in the imported taglib
// will be part of this taglib.
//
// NOTE: If a taglib import refers to a package.json file then we read
// the package.json file and automatically import *all* of the
// taglibs from the installed modules found in the "dependencies"
// section
var taglib = this.taglib;
var dirname = this.dirname;
var importPath;
if (imports && Array.isArray(imports)) {
for (var i=0; i<imports.length; i++) {
var curImport = imports[i];
if (typeof curImport === 'string') {
var basename = nodePath.basename(curImport);
if (basename === 'package.json') {
var packagePath = markoModules.resolveFrom(dirname, curImport);
var packageDir = nodePath.dirname(packagePath);
var pkg = jsonFileReader.readFileSync(packagePath);
var dependencies = pkg.dependencies;
if (dependencies) {
var dependencyNames = Object.keys(dependencies);
for (var j=0; j<dependencyNames.length; j++) {
var dependencyName = dependencyNames[j];
importPath = resolveFrom(packageDir, dependencyName + '/marko.json');
if (importPath) {
taglib.addImport(importPath);
}
}
}
} else {
importPath = resolveFrom(dirname, curImport);
if (importPath) {
taglib.addImport(importPath);
} else {
throw new Error('Import not fount: ' + curImport + ' (from ' + dirname + ')');
}
}
}
}
}
}
textTransformer(value) {
// Marko allows a "text-transformer" to be registered. The provided
// text transformer will be called for any static text found in a template.
var taglib = this.taglib;
var dirname = this.dirname;
var transformer = new types.Transformer();
if (typeof value === 'string') {
value = {
path: value
};
}
propertyHandlers(value, {
path(value) {
var path = markoModules.resolveFrom(dirname, value);
transformer.path = path;
}
}, this.dependencyChain.append('textTransformer').toString());
ok(transformer.path, '"path" is required for transformer');
taglib.addTextTransformer(transformer);
}
/**
* Allows an ID to be explicitly assigned to a taglib.
* The taglib ID is used to prevent the same taglib (even if different versions)
* from being loaded multiple times.
*
* NOTE: Introduced as part of fix for #73
*
* @param {String} value The taglib ID
*/
taglibId(value) {
var taglib = this.taglib;
taglib.id = value;
}
transformer(value) {
// Marko allows a "text-transformer" to be registered. The provided
// text transformer will be called for any static text found in a template.
var taglib = this.taglib;
var dirname = this.dirname;
var transformer = new types.Transformer();
Eif (typeof value === 'string') {
value = {
path: value
};
}
propertyHandlers(value, {
path(value) {
var path = markoModules.resolveFrom(dirname, value);
transformer.path = path;
}
}, this.dependencyChain.append('transformer').toString());
ok(transformer.path, '"path" is required for transformer');
taglib.addTransformer(transformer);
}
attributeGroups(value) {
let taglib = this.taglib;
let attributeGroups = taglib.attributeGroups || (taglib.attributeGroups = {});
let dependencyChain = this.dependencyChain.append('attribute-groups');
Object.keys(value).forEach((attrGroupName) => {
let attrGroup = attributeGroups[attrGroupName] = {};
let attrGroupDependencyChain = dependencyChain.append(attrGroupName);
let rawAttrGroup = value[attrGroupName];
Object.keys(rawAttrGroup).forEach((attrName) => {
var rawAttrDef = rawAttrGroup[attrName];
let attr = loaders.loadAttributeFromProps(
attrName,
rawAttrDef,
attrGroupDependencyChain.append('@' + attrName));
attrGroup[attrName] = attr;
});
});
}
}
function loadTaglibFromProps(taglib, taglibProps, dependencyChain) {
ok(taglib, '"taglib" is required');
ok(taglibProps, '"taglibProps" is required');
ok(taglib.filePath, '"taglib.filePath" is required');
Eif (!dependencyChain) {
dependencyChain = new DependencyChain([taglib.filePath]);
}
var taglibLoader = new TaglibLoader(taglib, dependencyChain);
try {
taglibLoader.load(taglibProps);
} catch(err) {
throw createError('Unable to load taglib (' + dependencyChain + '): ' + err, err);
}
return taglib;
}
module.exports = loadTaglibFromProps;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 1 1 106 1 1 1 1 1 1 1 1 1 1 1 | var types = require('./types');
function isSupportedAttributeProperty(propertyName) {
return exports.loadAttributeFromProps.isSupportedProperty(propertyName);
}
function isSupportedTagProperty(propertyName) {
return exports.loadTagFromProps.isSupportedProperty(propertyName);
}
function createTaglib(taglibPath) {
return new types.Taglib(taglibPath);
}
exports.createTaglib = createTaglib;
exports.loadAttributeFromProps = require('./loadAttributeFromProps');
exports.loadTagFromProps = require('./loadTagFromProps');
exports.loadTagFromFile = require('./loadTagFromFile');
exports.loadTaglibFromProps = require('./loadTaglibFromProps');
exports.loadTaglibFromFile = require('./loadTaglibFromFile');
exports.loadAttributes = require('./loadAttributes');
exports.isSupportedAttributeProperty = isSupportedAttributeProperty;
exports.isSupportedTagProperty = isSupportedTagProperty;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
const nodePath = require('path');
const fs = require('fs');
const stripJsonComments = require('strip-json-comments');
const tagDefFromCode = require('./tag-def-from-code');
const loaders = require('./loaders');
const fsReadOptions = { encoding: 'utf8' };
const extend = require('raptor-util/extend');
const types = require('./types');
const tagFileTypes = [
'template',
'renderer',
'transformer',
'code-generator',
'node-factory',
];
const searchFiles = [
{ name:'index.marko', type:'template' },
{ name:'renderer', type:'renderer' },
{ name:'index', type:'renderer' },
{ name:'template.marko', type:'template' },
{ name:'template.html', type:'template' },
{ name:'code-generator', type:'code-generator' },
{ name:'node-factory', type:'node-factory' },
{ name:'transformer', type:'transformer' },
];
function createDefaultTagDef() {
return {
attributes: {
'*': {
type: 'string',
targetProperty: null,
preserveName: false
}
}
};
}
function getFileMap(dirname) {
let fileMap = {};
let files = fs.readdirSync(dirname);
files.forEach(file => {
let extName = nodePath.extname(file);
let baseName = file.slice(0, -1*extName.length);
let fullPath = nodePath.join(dirname, file);
fileMap[baseName] = fileMap[baseName] || {};
fileMap[baseName][extName] = fullPath;
fileMap[file] = fileMap[file] || {};
fileMap[file].__path = fullPath;
});
return fileMap;
}
function getPath(filename, fileMap) {
let file = fileMap[filename];
if(!file) return;
if(file.__path) return file.__path;
if(file.js) return file['.js'];
return file[Object.keys(file)[0]];
}
function findAndSetFile(tagDef, tagDirname) {
if(!fs.statSync(tagDirname).isDirectory()) {
return;
}
let fileMap = getFileMap(tagDirname);
for(let i = 0; i < searchFiles.length; i++) {
let name = searchFiles[i].name;
let type = searchFiles[i].type;
let path = getPath(name, fileMap);
if(path) {
tagDef[type] = path;
return true;
}
}
}
function hasFile(tagDef) {
for(let i = 0; i < tagFileTypes.length; i++) {
if(tagDef[tagFileTypes[i]]) return true;
}
return false;
}
/**
* @param {String} tagsConfigPath path to tag definition file
* @param {String} tagsConfigDirname path to directory of tags config file (should be path.dirname(tagsConfigPath))
* @param {String|Object} dir the path to directory to scan
* @param {String} taglib the taglib that is being loaded
*/
module.exports = function scanTagsDir(tagsConfigPath, tagsConfigDirname, dir, taglib, dependencyChain) {
let prefix;
if (typeof dir === 'object') {
prefix = dir.prefix;
dir = dir.path;
}
if (prefix == null) {
// no prefix by default
prefix = '';
}
dir = nodePath.resolve(tagsConfigDirname, dir);
let children = fs.readdirSync(dir);
let rendererJSFile;
for (let i=0, len=children.length; i<len; i++) {
rendererJSFile = null;
let childFilename = children[i];
if (childFilename === 'node_modules') {
continue;
}
let tagName;
let tagDef = null;
let tagDirname;
let tagJsonPath;
let ext = nodePath.extname(childFilename);
if (ext === '.marko') {
tagName = childFilename.slice(0, 0 - ext.length);
tagDirname = dir;
tagDef = createDefaultTagDef();
tagDef.template = nodePath.join(dir, childFilename);
} else {
tagName = prefix + childFilename;
tagDirname = nodePath.join(dir, childFilename);
tagJsonPath = nodePath.join(tagDirname, 'marko-tag.json');
let hasTagJson = false;
if (fs.existsSync(tagJsonPath)) {
hasTagJson = true;
// marko-tag.json exists in the directory, use that as the tag definition
try {
tagDef = JSON.parse(stripJsonComments(fs.readFileSync(tagJsonPath, fsReadOptions)));
} catch(e) {
throw new Error('Unable to parse JSON file at path "' + tagJsonPath + '". Error: ' + e);
}
} else {
tagJsonPath = null;
tagDef = createDefaultTagDef();
}
if (!hasFile(tagDef)) {
let fileWasSet = findAndSetFile(tagDef, tagDirname);
if(!fileWasSet) {
if (hasTagJson) {
throw new Error('Invalid tag file: ' + tagJsonPath + '. Neither a renderer or a template was found for tag. ' + JSON.stringify(tagDef, null, 2));
} else {
// Skip this directory... there doesn't appear to be anything in it
continue;
}
}
}
if (!hasTagJson && (tagDef.renderer || tagDef.template)) {
let templateCode = fs.readFileSync(tagDef.renderer || tagDef.template, fsReadOptions);
let extractedTagDef = tagDefFromCode.extractTagDef(templateCode);
if (extractedTagDef) {
extend(tagDef, extractedTagDef);
}
}
}
let tagDependencyChain;
if (tagJsonPath) {
tagDependencyChain = dependencyChain.append(tagJsonPath);
} else {
tagDependencyChain = dependencyChain.append(tagDirname);
}
let tag = new types.Tag(tagJsonPath || tagDirname);
loaders.loadTagFromProps(tag, tagDef, tagDependencyChain);
tag.name = tag.name || tagName;
taglib.addTag(tag);
}
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | 1 1 1 1 | // Rather than using a full-blown JavaScript parser, we are going to use a few regular expressions
// to tokenize the code and find what we are interested in
var tagStartRegExp = /(^\s*(?:(?:exports.(?:tag|TAG))|(?:TAG))\s*=\s*)\{/m;
// Tokens: "<string>", '<string>', /*<some comment*/, //<single line comment>, {, }, ;
var tokensRegExp = /"(?:[^"]|\\")*"|'(?:[^'])|(\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\/)|(\/\/.*)|[\{\};]/g;
function extractTagDef(code) {
var startMatches = tagStartRegExp.exec(code);
var tagDefStart;
var tagDefEnd;
if (startMatches) {
tagDefStart = startMatches.index + startMatches[1].length;
var nextTokenMatches;
tokensRegExp.lastIndex = tagDefStart;
var depth = 0;
while ((nextTokenMatches = tokensRegExp.exec(code))) {
if (nextTokenMatches[0] === '{') {
depth++;
continue;
} else if (nextTokenMatches[0] === '}') {
if (--depth === 0) {
tagDefEnd = tokensRegExp.lastIndex;
break;
}
}
else if (nextTokenMatches[0] === ';') {
tagDefEnd = nextTokenMatches.index;
break;
}
}
if (tagDefStart != null && tagDefEnd != null) {
var jsTagDef = code.substring(tagDefStart, tagDefEnd);
var tagDefObject;
try {
// Try parsing it as JSON
tagDefObject = JSON.parse(jsTagDef);
} catch(e) {
// Try parsing it as JavaScript
try {
tagDefObject = eval('(' + jsTagDef + ')');
} catch(e) {
tagDefObject = {};
}
}
return tagDefObject;
}
} else {
return null;
}
}
exports.extractTagDef = extractTagDef;
|
| 1 2 3 4 5 6 7 8 | 1 1 1 1 1 1 1 | exports.Taglib = require('./Taglib');
exports.Tag = require('./Tag');
exports.Attribute = require('./Attribute');
exports.Property = require('./Property');
exports.NestedVariable = require('./NestedVariable');
exports.ImportedVariable = require('./ImportedVariable');
exports.Transformer = require('./Transformer');
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| TaglibLookup.js | 7.25% | (14 / 193) | 0% | (0 / 117) | 0% | (0 / 26) | 7.25% | (14 / 193) | |
| index.js | 45.95% | (17 / 37) | 12.5% | (1 / 8) | 20% | (1 / 5) | 45.95% | (17 / 37) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var ok = require('assert').ok;
var taglibTypes = require('../taglib-loader/types');
var Text = require('../ast/Text');
var extend = require('raptor-util/extend');
function transformerComparator(a, b) {
a = a.priority;
b = b.priority;
if (a == null) {
a = Number.MAX_VALUE;
}
if (b == null) {
b = Number.MAX_VALUE;
}
return a - b;
}
function TAG_COMPARATOR(a, b) {
a = a.name;
b = b.name;
return a.localeCompare(b);
}
function merge(target, source) {
for (var k in source) {
if (source.hasOwnProperty(k)) {
if (target[k] && typeof target[k] === 'object' &&
source[k] && typeof source[k] === 'object') {
if (source.__noMerge) {
// Don't merge objects that are explicitly marked as "do not merge"
continue;
}
if (Array.isArray(target[k]) || Array.isArray(source[k])) {
var targetArray = target[k];
var sourceArray = source[k];
if (!Array.isArray(targetArray)) {
targetArray = [targetArray];
}
if (!Array.isArray(sourceArray)) {
sourceArray = [sourceArray];
}
target[k] = [].concat(targetArray).concat(sourceArray);
} else {
var Ctor = target[k].constructor;
var newTarget = new Ctor();
merge(newTarget, target[k]);
merge(newTarget, source[k]);
target[k] = newTarget;
}
} else {
target[k] = source[k];
}
}
}
return target;
}
/**
* A taglib lookup merges in multiple taglibs so there is a single and fast lookup
* for custom tags and custom attributes.
*/
class TaglibLookup {
constructor() {
this.merged = {
attributeGroups: {}
};
this.taglibsById = {};
this._inputFiles = null;
this._sortedTags = undefined;
}
hasTaglib(taglib) {
return this.taglibsById.hasOwnProperty(taglib.id);
}
_mergeNestedTags(taglib) {
var Tag = taglibTypes.Tag;
// Loop over all of the nested tags and register a new custom tag
// with the fully qualified name
var merged = this.merged;
function handleNestedTags(tag, parentTagName) {
tag.forEachNestedTag(function(nestedTag) {
var fullyQualifiedName = parentTagName + ':' + nestedTag.name;
// Create a clone of the nested tag since we need to add some new
// properties
var clonedNestedTag = new Tag();
extend(clonedNestedTag, nestedTag);
// Record the fully qualified name of the parent tag that this
// custom tag is associated with.
clonedNestedTag.parentTagName = parentTagName;
clonedNestedTag.name = fullyQualifiedName;
merged.tags[fullyQualifiedName] = clonedNestedTag;
handleNestedTags(clonedNestedTag, fullyQualifiedName);
});
}
taglib.forEachTag(function(tag) {
handleNestedTags(tag, tag.name);
});
}
addTaglib(taglib) {
ok(taglib, '"taglib" is required');
ok(taglib.id, '"taglib.id" expected');
if (this.taglibsById.hasOwnProperty(taglib.id)) {
return;
}
// console.log("TAGLIB:", taglib);
this._sortedTags = undefined;
this.taglibsById[taglib.id] = taglib;
merge(this.merged, {
tags: taglib.tags,
transformers: taglib.transformers,
textTransformers: taglib.textTransformers,
attributes: taglib.attributes,
patternAttributes: taglib.patternAttributes,
attributeGroups: taglib.attributeGroups || {}
});
this._mergeNestedTags(taglib);
}
getTagsSorted() {
var sortedTags = this._sortedTags;
if (sortedTags === undefined) {
sortedTags = this._sortedTags = [];
this.forEachTag((tag) => {
sortedTags.push(tag);
});
sortedTags.sort(TAG_COMPARATOR);
}
return sortedTags;
}
forEachTag(callback) {
var tags = this.merged.tags;
if (tags) {
for (var tagName in tags) {
if (tags.hasOwnProperty(tagName)) {
var tag = tags[tagName];
var result = callback(tag);
if (result === false) {
break;
}
}
}
}
}
forEachAttribute(tagName, callback) {
var tags = this.merged.tags;
if (!tags) {
return;
}
var globalAttributes = this.merged.attributes;
var taglibAttributeGroups = this.merged.attributeGroups;
function findAttributesForTagName(tagName) {
var tag = tags[tagName];
if (!tag) {
return;
}
function handleAttr(attrDef) {
if (attrDef.ref) {
attrDef = globalAttributes[attrDef.ref];
}
callback(attrDef, tag);
}
var attributes = tag.attributes;
if (!attributes) {
return;
}
for (var attrName in attributes) {
if (attributes.hasOwnProperty(attrName)) {
handleAttr(attributes[attrName], tag);
}
}
if (tag.attributeGroups) {
for (let i=0; i<tag.attributeGroups.length; i++) {
let attributeGroupName = tag.attributeGroups[i];
let attributeGroup = taglibAttributeGroups[attributeGroupName];
if (attributeGroup) {
for (let attrName in attributeGroup) {
handleAttr(attributeGroup[attrName]);
}
}
}
}
if (tag.patternAttributes) {
tag.patternAttributes.forEach(handleAttr);
}
}
findAttributesForTagName(tagName); // Look for an exact match at the tag level
findAttributesForTagName('*'); // Including attributes that apply to all tags
}
getTag(element) {
if (typeof element === 'string') {
element = {
tagName: element
};
}
var tags = this.merged.tags;
if (!tags) {
return;
}
var tagName = element.tagName;
return tags[tagName];
}
getAttribute(element, attr) {
if (typeof element === 'string') {
element = {
tagName: element
};
}
if (typeof attr === 'string') {
attr = {
name: attr
};
}
var tags = this.merged.tags;
if (!tags) {
return;
}
var taglibAttributeGroups = this.merged.attributeGroups;
var tagName = element.tagName;
var attrName = attr.name;
function findAttributeForTag(tag, attributes, attrName) {
// try by exact match first
var attribute = attributes[attrName];
if (attribute === undefined) {
if (tag.attributeGroups) {
for (let i=0; i<tag.attributeGroups.length; i++) {
let attributeGroupName = tag.attributeGroups[i];
let attributeGroup = taglibAttributeGroups[attributeGroupName];
if (attributeGroup) {
attribute = attributeGroup[attrName];
if (attribute !== undefined) {
break;
}
}
}
}
}
if (attribute === undefined && attrName !== '*') {
if (tag.patternAttributes) {
// try searching by pattern
for (var i = 0, len = tag.patternAttributes.length; i < len; i++) {
var patternAttribute = tag.patternAttributes[i];
if (patternAttribute.pattern.test(attrName)) {
attribute = patternAttribute;
break;
}
}
}
}
return attribute;
}
var globalAttributes = this.merged.attributes;
function tryAttribute(tagName, attrName) {
var tag = tags[tagName];
if (!tag) {
return undefined;
}
return findAttributeForTag(tag, tag.attributes, attrName);
}
var attrDef = tryAttribute(tagName, attrName) || // Look for an exact match at the tag level
tryAttribute('*', attrName) || // If not there, see if there is a exact match on the attribute name for attributes that apply to all tags
tryAttribute(tagName, '*'); // Otherwise, see if there is a splat attribute for the tag
if (attrDef && attrDef.ref) {
attrDef = globalAttributes[attrDef.ref];
}
return attrDef;
}
forEachTemplateTransformer(callback, thisObj) {
var transformers = this.merged.transformers;
if (transformers && transformers.length) {
transformers.forEach(callback, thisObj);
}
}
forEachNodeTransformer(node, callback, thisObj) {
/*
* Based on the type of node we have to choose how to transform it
*/
if (node.tagName || node.tagNameExpression) {
this.forEachTagTransformer(node, callback, thisObj);
} else if (node instanceof Text) {
this.forEachTextTransformer(callback, thisObj);
}
}
forEachTagTransformer(element, callback, thisObj) {
if (typeof element === 'string') {
element = {
tagName: element
};
}
var tagName = element.tagName;
/*
* If the node is an element node then we need to find all matching
* transformers based on the URI and the local name of the element.
*/
var transformers = [];
function addTransformer(transformer) {
if (!transformer || !transformer.getFunc) {
throw new Error('Invalid transformer');
}
transformers.push(transformer);
}
/*
* Handle all of the transformers for all possible matching transformers.
*
* Start with the least specific and end with the most specific.
*/
if (this.merged.tags) {
if (tagName) {
if (this.merged.tags[tagName]) {
this.merged.tags[tagName].forEachTransformer(addTransformer);
}
}
if (this.merged.tags['*']) {
this.merged.tags['*'].forEachTransformer(addTransformer);
}
}
transformers.sort(transformerComparator);
transformers.forEach(callback, thisObj);
}
forEachTextTransformer(callback, thisObj) {
if (this.merged.textTransformers) {
this.merged.textTransformers.sort(transformerComparator);
this.merged.textTransformers.forEach(callback, thisObj);
}
}
getInputFiles() {
if (!this._inputFiles) {
var inputFilesSet = {};
for (var taglibId in this.taglibsById) {
if (this.taglibsById.hasOwnProperty(taglibId)) {
var taglibInputFiles = this.taglibsById[taglibId].getInputFiles();
var len = taglibInputFiles.length;
if (len) {
for (var i=0; i<len; i++) {
inputFilesSet[taglibInputFiles[i]] = true;
}
}
}
}
this._inputFiles = Object.keys(inputFilesSet);
}
return this._inputFiles;
}
toString() {
return 'lookup: ' + this.getInputFiles().join(', ');
}
}
module.exports = TaglibLookup;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | 1 1 1 1 1 1 1 1 1 1 1 7 7 1 1 1 1 | 'use strict';
exports.registerTaglib = registerTaglib;
exports.buildLookup = buildLookup;
exports.clearCache = clearCache;
var taglibLoader;
var taglibFinder;
var TaglibLookup;
exports.registeredTaglibs = [];
var lookupCache = {};
function handleImports(lookup, taglib) {
if (taglib.imports) {
for (var i=0; i<taglib.imports.length; i++) {
var importedTaglib = taglib.imports[i];
if (!lookup.hasTaglib(importedTaglib)) {
lookup.addTaglib(importedTaglib);
}
}
}
}
function buildLookup(dirname) {
var taglibs = taglibFinder.find(dirname, exports.registeredTaglibs);
var lookupCacheKey = taglibs
.map(function(taglib) {
return taglib.id;
})
.join(',');
var lookup = lookupCache[lookupCacheKey];
if (lookup === undefined) {
lookup = new TaglibLookup();
// The taglibs "closer" to the template will be earlier in the list
// and the taglibs "farther" from the template will be later. We
// want closer taglibs to take precedence (especially when de-duping)
// so we loop from beginning to end. We used to loop from the end
// to the beginning, but that appears to have been a mistake.
for (var i=0; i<taglibs.length; i++) {
var taglib = taglibs[i];
lookup.addTaglib(taglib);
handleImports(lookup, taglib);
}
lookupCache[lookupCacheKey] = lookup;
}
return lookup;
}
function registerTaglib(taglib) {
Iif (typeof taglib === 'string') {
let taglibPath = taglib;
taglib = taglibLoader.loadFromFile(taglibPath);
}
exports.registeredTaglibs.push(taglib);
}
function clearCache() {
lookupCache = {};
}
taglibLoader = require('../taglib-loader');
taglibFinder = require('../taglib-finder');
TaglibLookup = require('./TaglibLookup');
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| PosInfo.js | 27.27% | (3 / 11) | 0% | (0 / 4) | 0% | (0 / 3) | 27.27% | (3 / 11) | |
| UniqueVars.js | 10.53% | (2 / 19) | 0% | (0 / 6) | 0% | (0 / 2) | 10.53% | (2 / 19) | |
| adjustIndent.js | 16.22% | (6 / 37) | 0% | (0 / 22) | 0% | (0 / 3) | 16.22% | (6 / 37) | |
| deresolve.js | 100% | (1 / 1) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (1 / 1) | |
| finger-print.js | 66.67% | (2 / 3) | 100% | (0 / 0) | 0% | (0 / 1) | 66.67% | (2 / 3) | |
| html-elements.js | 27.91% | (12 / 43) | 0% | (0 / 17) | 0% | (0 / 4) | 27.91% | (12 / 43) | |
| isCompoundExpression.js | 40% | (2 / 5) | 0% | (0 / 2) | 0% | (0 / 1) | 40% | (2 / 5) | |
| isJavaScriptReservedWord.js | 66.67% | (2 / 3) | 100% | (0 / 0) | 0% | (0 / 1) | 66.67% | (2 / 3) | |
| isValidJavaScriptIdentifier.js | 66.67% | (2 / 3) | 100% | (0 / 0) | 0% | (0 / 1) | 66.67% | (2 / 3) | |
| isValidJavaScriptVarName.js | 50% | (3 / 6) | 0% | (0 / 2) | 0% | (0 / 1) | 50% | (3 / 6) | |
| javaScriptReservedWords.js | 100% | (1 / 1) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (1 / 1) | |
| macros.js | 10% | (4 / 40) | 0% | (0 / 18) | 0% | (0 / 6) | 10% | (4 / 40) | |
| parseExpression.js | 66.67% | (2 / 3) | 100% | (0 / 0) | 0% | (0 / 1) | 66.67% | (2 / 3) | |
| parseJavaScript.js | 3.09% | (5 / 162) | 0% | (0 / 110) | 0% | (0 / 2) | 3.09% | (5 / 162) | |
| parseJavaScriptArgs.js | 42.86% | (3 / 7) | 100% | (0 / 0) | 0% | (0 / 1) | 42.86% | (3 / 7) | |
| parseStatement.js | 66.67% | (2 / 3) | 100% | (0 / 0) | 0% | (0 / 1) | 66.67% | (2 / 3) | |
| removeComments.js | 15.38% | (2 / 13) | 0% | (0 / 4) | 0% | (0 / 1) | 15.38% | (2 / 13) | |
| removeDashes.js | 33.33% | (1 / 3) | 100% | (0 / 0) | 0% | (0 / 2) | 33.33% | (1 / 3) | |
| replacePlaceholderEscapeFuncs.js | 22.22% | (2 / 9) | 0% | (0 / 8) | 0% | (0 / 2) | 22.22% | (2 / 9) | |
| safeVarName.js | 20% | (2 / 10) | 0% | (0 / 2) | 0% | (0 / 2) | 20% | (2 / 10) | |
| tokenizer.js | 37.5% | (6 / 16) | 0% | (0 / 2) | 33.33% | (1 / 3) | 37.5% | (6 / 16) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 1 1 1 | 'use strict';
var path = require('path');
function getRelativePath(absolutePath) {
if (typeof window === 'undefined') {
absolutePath = path.resolve(process.cwd(), absolutePath);
return path.relative(process.cwd(), absolutePath);
} else {
return absolutePath;
}
}
class PosInfo {
constructor(path, line, column) {
this.path = getRelativePath(path);
this.line = line;
this.column = column;
}
toString() {
return this.path + (this.line != null ? (":" + this.line + ":" + this.column) : '');
}
}
module.exports = PosInfo;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | 1 1 | 'use strict';
var safeVarName = require('./safeVarName');
class UniqueVars {
constructor() {
this.vars = {};
}
addVar(name, value) {
if (typeof value !== 'string') {
// Convert the non-string value into a string for easy comparison
value = JSON.stringify(value);
}
name = safeVarName(name);
var entry = this.vars[name];
if (entry) {
var vars = entry.vars;
// See if there is already a variable with the requested value
for (var i=0; i<vars.length; i++) {
var curVar = vars[i];
if (curVar.value === value) {
return curVar.name;
}
}
let newEntry = {
name: name + (++entry.counter),
value: value
};
entry.vars.push(newEntry);
return newEntry.name;
} else {
entry = {
vars: [
{
name: name,
value: value
}
],
counter: 1
};
this.vars[name] = entry;
}
return name;
}
}
module.exports = UniqueVars;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | 1 1 1 1 1 1 | var splitLinesRegExp = /\r?\n/; var initialIndentationRegExp = /^\s+/; function removeInitialEmptyLines(lines) { var i; for (i=0; i<lines.length; i++) { if (lines[i].trim() !== '') { break; } } if (i !== 0) { lines = lines.slice(i); } return lines; } function removeTrailingEmptyLines(lines) { var i; var last = lines.length-1; for (i=last; i>=0; i--) { if (lines[i].trim() !== '') { break; } } if (i !== last) { lines = lines.slice(0, i+1); } return lines; } function adjustIndent(str, newIndentation) { if (!str) { return str; } var lines = str.split(splitLinesRegExp); lines = removeInitialEmptyLines(lines); lines = removeTrailingEmptyLines(lines); if (lines.length === 0) { return ''; } var initialIndentationMatches = initialIndentationRegExp.exec(lines[0]); var indentation = initialIndentationMatches ? initialIndentationMatches[0] : ''; if (!indentation && !newIndentation) { return str; } lines.forEach((line, i) => { if (line.startsWith(indentation)) { line = line.substring(indentation.length); } lines[i] = line; }); return newIndentation ? lines.join('\n' + newIndentation) : lines.join('\n'); } module.exports = adjustIndent; |
| 1 2 | 1 | module.exports = require('deresolve');
|
| 1 2 3 4 5 6 | 1 1 | var sha1 = require('simple-sha1');
module.exports = function(str) {
return sha1.sync(str);
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | 1 1 1 1 1 1 1 1 1 1 1 1 |
var lassoPackageRoot = require('lasso-package-root');
var path = require('path');
var lassoCachingFS = require('lasso-caching-fs');
var fs = require('fs');
var stripJsonComments = require('strip-json-comments');
var fsReadOptions = { encoding: 'utf8' };
function parseJSONFile(path) {
var json = fs.readFileSync(path, fsReadOptions);
try {
var taglibProps = JSON.parse(stripJsonComments(json));
return taglibProps;
} catch(e) {
throw new Error('Unable to parse JSON file at path "' + path + '". Error: ' + e);
}
}
function loadTags(file) {
var raw = parseJSONFile(file);
var tags = {};
for (var k in raw) {
if (raw.hasOwnProperty(k)) {
if (k.charAt(0) === '<' && k.charAt(k.length - 1) === '>') {
var tagName = k.substring(1, k.length - 1);
tags[tagName] = true;
}
}
}
return tags;
}
var cache = {};
function getPackageRootDir(dirname) {
try {
return lassoPackageRoot.getRootDir(dirname);
} catch(e) {
return undefined;
}
}
function isRegisteredElement(tagName, dir) {
var packageRootDir = getPackageRootDir(dir);
var currentDir = dir;
while (true) {
var filePath = path.join(currentDir, 'html-elements.json');
if (lassoCachingFS.existsSync(filePath)) {
var tags = cache[filePath];
if (!tags) {
tags = cache[filePath] = loadTags(filePath);
}
if (tags[tagName]) {
return true;
}
}
var parentDir = path.dirname(currentDir);
if (!parentDir || parentDir === currentDir || parentDir === packageRootDir) {
break;
}
currentDir = parentDir;
}
return false;
}
exports.isRegisteredElement = isRegisteredElement;
|
| 1 2 3 4 5 6 7 8 9 10 11 | 1 1 | function isCompoundExpression(expression) { if (typeof expression === 'string') { // TBD: Should we use Esprima to parse the expression string to see if it is a compount expression? return true; } return expression.isCompoundExpression(); } module.exports = isCompoundExpression; |
| 1 2 3 4 5 6 7 | 1 1 | var reservedWords = require('./javaScriptReservedWords');
module.exports = function isJavaScriptReservedWord(varName) {
return reservedWords[varName] === true;
};
|
| 1 2 3 4 5 6 7 | 1 1 | var idRegExp = /^[$A-Z_][0-9A-Z_$]*$/i; module.exports = function isValidJavaScriptIdentifier(varName) { return idRegExp.test(varName); }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 | 1 1 1 | var reservedWords = require('./javaScriptReservedWords');
var varNameRegExp = /^[$A-Z_][0-9A-Z_$]*$/i;
module.exports = function isValidJavaScriptVarName(varName) {
if (reservedWords[varName]) {
return false;
}
return varNameRegExp.test(varName);
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | 1 | module.exports = {
'abstract': true,
'arguments': true,
'await': true, // Not really a reserved word but we add it here anyway
'boolean': true,
'break': true,
'byte': true,
'case': true,
'catch': true,
'char': true,
'class': true,
'const': true,
'continue': true,
'debugger': true,
'default': true,
'delete': true,
'do': true,
'double': true,
'else': true,
'enum*': true,
'eval': true,
'export': true,
'extends': true,
'false': true,
'final': true,
'finally': true,
'float': true,
'for': true,
'function': true,
'goto': true,
'if': true,
'implements': true,
'import': true,
'in': true,
'instanceof': true,
'int': true,
'interface': true,
'let': true,
'long': true,
'native': true,
'new': true,
'null': true,
'package': true,
'private': true,
'protected': true,
'public': true,
'return': true,
'short': true,
'static': true,
'super': true,
'switch': true,
'synchronized': true,
'this': true,
'throw': true,
'throws': true,
'transient': true,
'true': true,
'try': true,
'typeof': true,
'var': true,
'void': true,
'volatile': true,
'while': true,
'with': true,
'yield': true
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | 1 1 1 1 | 'use strict';
var safeVarName = require('./safeVarName');
var ok = require('assert').ok;
class MacrosContext {
constructor() {
this._byName = {};
}
isMacro(name) {
if (!name) {
return false;
}
if (name.type === 'Literal') {
name = name.value;
}
return this._byName.hasOwnProperty(name);
}
getRegisteredMacro(name) {
return this._byName[name];
}
registerMacro(name, params) {
ok(name, '"name" is required');
ok(typeof name === 'string', '"name" should be a string');
if (params == null) {
params = [];
} else {
ok(Array.isArray(params), '"params" should be an array');
}
var hasOut = false;
var hasRenderBody = false;
params.forEach((param) => {
if (param === 'out') {
hasOut = true;
} else if (param === 'renderBody') {
hasRenderBody = true;
}
});
if (!hasOut) {
params.push('out');
}
if (!hasRenderBody) {
params.push('renderBody');
}
var paramIndexes = {};
params.forEach((param, i) => {
paramIndexes[param] = i;
if (param === 'out') {
hasOut = true;
} else if (param === 'renderBody') {
hasRenderBody = true;
}
});
var functionName = 'macro_' + safeVarName(name);
var macroDef = {
name: name,
params: params,
functionName: functionName,
getParamIndex: function(param) {
return paramIndexes[param];
}
};
this._byName[name] = macroDef;
return macroDef;
}
}
function createMacrosContext() {
return new MacrosContext();
}
exports.createMacrosContext = createMacrosContext;
|
| 1 2 3 4 5 6 | 1 1 | var parseJavaScript = require('./parseJavaScript');
module.exports = function(src, builder) {
return parseJavaScript(src, builder, true /* isExpression */ );
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | 1 1 1 1 1 | 'use strict';
var ok = require('assert').ok;
const esprima = require('esprima');
function parseExpression(src, builder, isExpression) {
ok(typeof src === 'string', '"src" should be a string expression');
ok(builder, '"builder" is required');
function convert(node) {
if (Array.isArray(node)) {
let nodes = node;
for (let i=0; i<nodes.length; i++) {
var converted = convert(nodes[i]);
if (converted == null) {
return null;
}
nodes[i] = converted;
}
return nodes;
}
switch(node.type) {
case 'ArrayExpression': {
let elements = convert(node.elements);
if (!elements) {
return null;
}
return builder.arrayExpression(elements);
}
case 'AssignmentExpression': {
let left = convert(node.left);
if (!left) {
return null;
}
let right = convert(node.right);
if (!right) {
return null;
}
return builder.assignment(left, right, node.operator);
}
case 'BinaryExpression': {
let left = convert(node.left);
if (!left) {
return null;
}
let right = convert(node.right);
if (!right) {
return null;
}
return builder.binaryExpression(left, node.operator, right);
}
case 'BlockStatement': {
let body = convert(node.body);
if (!body) {
return null;
}
return body;
}
case 'CallExpression': {
let callee = convert(node.callee);
if (!callee) {
return null;
}
let args = convert(node.arguments);
if (!args) {
return null;
}
return builder.functionCall(callee, args);
}
case 'ConditionalExpression': {
let test = convert(node.test);
if (!test) {
return null;
}
let consequent = convert(node.consequent);
if (!consequent) {
return null;
}
let alternate = convert(node.alternate);
if (!alternate) {
return null;
}
return builder.conditionalExpression(test, consequent, alternate);
}
case 'ExpressionStatement': {
return convert(node.expression);
}
case 'FunctionDeclaration':
case 'FunctionExpression': {
let name = null;
if (node.id) {
name = convert(node.id);
if (name == null) {
return null;
}
}
let params = convert(node.params);
if (!params) {
return null;
}
let body = convert(node.body);
if (!body) {
return null;
}
return builder.functionDeclaration(name, params, body);
}
case 'Identifier': {
return builder.identifier(node.name);
}
case 'Literal': {
let literalValue;
if (node.regex) {
literalValue = new RegExp(node.regex.pattern, node.regex.flags);
} else {
literalValue = node.value;
}
return builder.literal(literalValue);
}
case 'LogicalExpression': {
let left = convert(node.left);
if (!left) {
return null;
}
let right = convert(node.right);
if (!right) {
return null;
}
return builder.logicalExpression(left, node.operator, right);
}
case 'MemberExpression': {
let object = convert(node.object);
if (!object) {
return null;
}
let property = convert(node.property);
if (!property) {
return null;
}
return builder.memberExpression(object, property, node.computed);
}
case 'NewExpression': {
let callee = convert(node.callee);
if (!callee) {
return null;
}
let args = convert(node.arguments);
if (!args) {
return null;
}
return builder.newExpression(callee, args);
}
case 'Program': {
if (node.body && node.body.length === 1) {
return convert(node.body[0]);
}
return null;
}
case 'ObjectExpression': {
let properties = convert(node.properties);
if (!properties) {
return null;
}
return builder.objectExpression(properties);
}
case 'Property': {
let key = convert(node.key);
if (!key) {
return null;
}
let value = convert(node.value);
if (!value) {
return null;
}
return builder.property(key, value);
}
case 'ReturnStatement': {
var argument = node.argument;
if (argument != null) {
argument = convert(node.argument);
if (!argument) {
return null;
}
}
return builder.returnStatement(argument);
}
case 'ThisExpression': {
return builder.thisExpression();
}
case 'UnaryExpression': {
let argument = convert(node.argument);
if (!argument) {
return null;
}
return builder.unaryExpression(argument, node.operator, node.prefix);
}
case 'UpdateExpression': {
let argument = convert(node.argument);
if (!argument) {
return null;
}
return builder.updateExpression(argument, node.operator, node.prefix);
}
case 'VariableDeclarator': {
var id = convert(node.id);
if (!id) {
return null;
}
var init;
if (node.init) {
init = convert(node.init);
if (!init) {
return null;
}
}
return builder.variableDeclarator(id, init);
}
case 'VariableDeclaration': {
var kind = node.kind;
var declarations = convert(node.declarations);
if (!declarations) {
return null;
}
return builder.vars(declarations, kind);
}
default:
return null;
}
}
let jsAST;
try {
if (isExpression) {
src = '(' + src + ')';
}
jsAST = esprima.parse(src);
} catch(e) {
if (e.index == null) {
// Doesn't look like an Esprima parse error... just rethrow the exception
throw e;
}
var errorIndex = e.index;
var errorMessage = '\n' + e.description;
if (errorIndex != null && errorIndex >= 0) {
if (isExpression) {
errorIndex--; // Account for extra paren added to start
}
errorMessage += ': ';
errorMessage += src + '\n'+ new Array(errorMessage.length + errorIndex + 1).join(" ") + '^';
}
var wrappedError = new Error(errorMessage);
wrappedError.index = errorIndex;
wrappedError.src = src;
wrappedError.code = 'ERR_INVALID_JAVASCRIPT_EXPRESSION';
throw wrappedError;
}
var converted = convert(jsAST);
if (converted == null) {
converted = builder.expression(src);
}
return converted;
}
module.exports = parseExpression;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 1 1 1 | 'use strict';
var ok = require('assert').ok;
function parseJavaScriptArgs(args, builder) {
ok(typeof args === 'string', '"args" should be a string');
ok(builder, '"builder" is required');
var parsed = builder.parseExpression('[' + args + ']');
return parsed.elements;
}
module.exports = parseJavaScriptArgs;
|
| 1 2 3 4 5 6 | 1 1 | var parseJavaScript = require('./parseJavaScript');
module.exports = function(src, builder) {
return parseJavaScript(src, builder, false /* isExpression */ );
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | 1 1 | 'use strict';
var tokenizer = require('./tokenizer').create([
{
name: 'stringDouble',
pattern: /"(?:[^"]|\\")*"/,
},
{
name: 'stringSingle',
pattern: /'(?:[^']|\\')*'/
},
{
name: 'singleLineComment',
pattern: /\/\/.*/
},
{
name: 'multiLineComment',
pattern: /\/\*(?:[\s\S]*?)\*\//
}
]);
/**
* Parses a for loop string in the following forms:
*
* <varName> in <expression>
* <varName> in <expression> | status-var=<varName> separator=<expression>
* <varName> from <expression> to <expression>
* <varName> from <expression> to <expression> step <expression>
* <init>; <test>; <update>
*/
module.exports = function removeComments(str) {
var comments = [];
tokenizer.forEachToken(str, (token) => {
switch(token.name) {
case 'singleLineComment':
case 'multiLineComment':
comments.push(token);
break;
}
});
var len = comments.length;
if (len) {
for (var i=len-1; i>=0; i--) {
var comment = comments[i];
str = str.substring(0, comment.start) + str.substring(comment.end);
}
}
return str;
};
|
| 1 2 3 4 5 6 | 1 | module.exports = function removeDashes(str) { return str.replace(/-([a-z])/g, function (match, lower) { return lower.toUpperCase(); }); }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 1 1 | var AttributePlaceholder = require('../ast/AttributePlaceholder');
module.exports = function replacePlaceholderEscapeFuncs(node, context) {
var walker = context.createWalker({
exit: function(node, parent) {
if (node.type === 'FunctionCall' &&
node.callee.type === 'Identifier') {
if (node.callee.name === '$noEscapeXml') {
return new AttributePlaceholder({escape: false, value: node.args[0]});
} else if (node.callee.name === '$escapeXml') {
return new AttributePlaceholder({escape: true, value: node.args[0]});
}
}
}
});
return walker.walk(node);
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 1 1 | function safeVarName(varName) { var parts = varName.split(/[\\/]/); if (parts.length >= 2) { // The varname looks like it was based on a path. // Let's just use the last two parts varName = parts.slice(-2).join('_'); } return varName.replace(/[^A-Za-z0-9_]/g, '_').replace(/^[0-9]+/, function(match) { var str = ''; for (var i=0; i<match.length; i++) { str += '_'; } return str; }); } module.exports = safeVarName; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 1 1 2 18 2 1 | 'use strict';
function create(tokens) {
function getToken(matches) {
for (var i=0; i<tokens.length; i++) {
let tokenValue = matches[i + 1];
if (tokenValue != null) {
var tokenDef = tokens[i];
return {
start: matches.index,
end: matches.index + matches[0].length,
name: tokenDef.name,
value: tokenValue
};
}
}
}
var tokensRegExp = new RegExp(tokens
.map((token) => {
return '(' + token.pattern.source + ')';
})
.join('|'), 'g');
return {
forEachToken: function(value, callback, thisObj) {
tokensRegExp.lastIndex = 0; // Start searching from the beginning again
var matches;
while ((matches = tokensRegExp.exec(value))) {
let token = getToken(matches);
callback.call(this, token);
}
}
};
}
exports.create = create;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| VDOMOptimizer.js | 14.29% | (9 / 63) | 0% | (0 / 18) | 0% | (0 / 10) | 14.29% | (9 / 63) | |
| index.js | 63.64% | (7 / 11) | 0% | (0 / 2) | 0% | (0 / 1) | 63.64% | (7 / 11) | |
| isStaticValue.js | 23.08% | (6 / 26) | 0% | (0 / 16) | 0% | (0 / 3) | 23.08% | (6 / 26) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | 1 1 1 1 1 1 1 1 1 | 'use strict';
/*
Algorithm:
Walk the DOM tree to find all HtmlElementVDOM and TextVDOM nodes
a) If a node is static then move to a static variable. Depending on whether or not the node is a root or nested,
we will need to replace it with one of the following:
- out.n(staticVar)
- .n(staticVar)
b) If a node is HTML-only then generate code depending on if it is root or not:
- out.e('div', ...) | out.t('foo')
- .e('div', ...) || .t('foo')
c) Else, generate one of the following:
- out.beginElement()
*/
const Node = require('../../ast/Node');
const OPTIMIZER_CONTEXT_KEY = Symbol();
const OPTIONS_DEFAULT = { optimizeTextNodes: true, optimizeStaticNodes: true };
const OPTIONS_OPTIMIZE_TEXT_NODES = { optimizeTextNodes: true, optimizeStaticNodes: false };
class OptimizerContext {
constructor(context) {
this.context = context;
this.nextAttrsId = 0;
this.nextNodeId = 0;
this._nextConstIdFunc = null;
}
get nextConstIdFunc() {
let nextConstIdFunc = this._nextConstIdFunc;
if (!nextConstIdFunc) {
let context = this.context;
let builder = context.builder;
let constId = this.context.helper('const');
let fingerprintLiteral = builder.literal(context.getFingerprint(6));
nextConstIdFunc = this._nextConstIdFunc = context.addStaticVar(
'marko_const_nextId',
builder.functionCall(constId, [ fingerprintLiteral ]));
}
return nextConstIdFunc;
}
}
class NodeVDOM extends Node {
constructor(variableIdentifier) {
super('NodeVDOM');
this.variableIdentifier = variableIdentifier;
}
writeCode(writer) {
var builder = writer.builder;
let funcCall = builder.functionCall(
builder.identifier('n'),
[
this.variableIdentifier
]);
if (this.isChild) {
writer.write('.');
} else {
writer.write('out.');
}
writer.write(funcCall);
}
}
function generateNodesForArray(nodes, context, options) {
let builder = context.builder;
var optimizerContext = context[OPTIMIZER_CONTEXT_KEY] ||
(context[OPTIMIZER_CONTEXT_KEY] = new OptimizerContext(context));
var optimizeStaticNodes = options.optimizeStaticNodes !== false;
function generateStaticNode(node) {
if (node.type === 'HtmlElementVDOM') {
node.createElementId = context.helper('createElement');
}/* else {
node.createTextId = context.importModule('marko_createText', 'marko/vdom/createText');
}*/
node.nextConstId = builder.functionCall(optimizerContext.nextConstIdFunc, []);
node.isStaticRoot = true;
let staticNodeId = context.addStaticVar('marko_node' + (optimizerContext.nextNodeId++), node);
return new NodeVDOM(staticNodeId);
}
function handleStaticAttributes(node) {
var attributesArg = node.attributesArg;
if (attributesArg) {
node.isStaticRoot = true;
let staticAttrsId = context.addStaticVar('marko_attrs' + (optimizerContext.nextAttrsId++), attributesArg);
node.attributesArg = staticAttrsId;
}
}
let finalNodes = [];
let i = 0;
while (i<nodes.length) {
let node = nodes[i];
if (node.type === 'HtmlElementVDOM') {
if (optimizeStaticNodes) {
if (node.isStatic) {
finalNodes.push(generateStaticNode(node));
doOptimizeNode(node, context, OPTIONS_OPTIMIZE_TEXT_NODES);
} else {
if (node.isAttrsStatic) {
handleStaticAttributes(node);
}
finalNodes.push(node);
}
} else {
finalNodes.push(node);
}
} else {
finalNodes.push(node);
}
i++;
}
return finalNodes;
}
function doOptimizeNode(node, context, options) {
let walker = context.createWalker({
enterArray(nodes) {
return generateNodesForArray(nodes, context, options);
}
});
return walker.walk(node);
}
class VDOMOptimizer {
optimize(node, context) {
doOptimizeNode(node, context, OPTIONS_DEFAULT);
}
}
module.exports = VDOMOptimizer;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 1 1 1 1 1 1 1 | 'use strict';
const VDOMOptimizer = require('./VDOMOptimizer');
const isStaticValue = require('./isStaticValue');
const OPTIMIZER_ADDED_KEY = Symbol();
function registerOptimizer(context) {
var data = context.data;
if (!data[OPTIMIZER_ADDED_KEY]) {
data[OPTIMIZER_ADDED_KEY] = true;
context.addOptimizer(new VDOMOptimizer());
}
}
exports.registerOptimizer = registerOptimizer;
exports.isStaticValue = isStaticValue;
exports.registerOptimizer = registerOptimizer;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 1 1 1 1 1 1 | 'use strict';
var Literal = require('../../ast/Literal');
var Node = require('../../ast/Node');
function isStaticArray(array) {
for (let i=0; i<array.length; i++) {
if (!isStaticValue(array[i])) {
return false;
}
}
return true;
}
function isStaticObject(object) {
for (var k in object) {
if (object.hasOwnProperty(k)) {
let v = object[k];
if (!isStaticValue(v)) {
return false;
}
}
}
}
function isStaticValue(value) {
if (value == null) {
return true;
}
if (value instanceof Node) {
if (value instanceof Literal) {
return isStaticValue(value.value);
} else {
return false;
}
} else {
if (typeof value === 'object') {
if (Array.isArray(value)) {
return isStaticArray(value);
} else {
return isStaticObject(value);
}
} else {
return true;
}
}
}
module.exports = isStaticValue;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| Component.js | 13.33% | (42 / 315) | 0% | (0 / 142) | 4% | (2 / 50) | 13.33% | (42 / 315) | |
| ComponentDef.js | 17.74% | (11 / 62) | 0% | (0 / 26) | 0% | (0 / 9) | 17.74% | (11 / 62) | |
| ComponentsContext.js | 16.13% | (10 / 62) | 0% | (0 / 20) | 0% | (0 / 9) | 16.13% | (10 / 62) | |
| State.js | 10.2% | (5 / 49) | 0% | (0 / 16) | 0% | (0 / 8) | 10.2% | (5 / 49) | |
| attach-detach.js | 27.78% | (10 / 36) | 0% | (0 / 12) | 0% | (0 / 5) | 27.78% | (10 / 36) | |
| boot.js | 100% | (1 / 1) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (1 / 1) | |
| bubble.js | 100% | (1 / 1) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (1 / 1) | |
| defineComponent.js | 22.22% | (6 / 27) | 0% | (0 / 8) | 0% | (0 / 4) | 23.08% | (6 / 26) | |
| event-delegation.js | 25% | (15 / 60) | 0% | (0 / 26) | 0% | (0 / 8) | 25% | (15 / 60) | |
| index-browser.js | 92.31% | (12 / 13) | 100% | (0 / 0) | 0% | (0 / 1) | 92.31% | (12 / 13) | |
| index.js | 11.63% | (10 / 86) | 0% | (0 / 38) | 0% | (0 / 6) | 11.76% | (10 / 85) | |
| init-components-browser.js | 8.91% | (9 / 101) | 0% | (0 / 40) | 0% | (0 / 12) | 8.91% | (9 / 101) | |
| init-components.js | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (0 / 0) | |
| loadComponent-dynamic.js | 50% | (1 / 2) | 100% | (0 / 0) | 0% | (0 / 1) | 50% | (1 / 2) | |
| loadComponent.js | 50% | (1 / 2) | 100% | (0 / 0) | 0% | (0 / 1) | 50% | (1 / 2) | |
| nextRepeatedId.js | 22.22% | (2 / 9) | 0% | (0 / 4) | 0% | (0 / 1) | 22.22% | (2 / 9) | |
| registry-browser.js | 28.95% | (11 / 38) | 0% | (0 / 12) | 0% | (0 / 4) | 28.95% | (11 / 38) | |
| registry.js | 16.67% | (6 / 36) | 0% | (0 / 14) | 0% | (0 / 8) | 16.67% | (6 / 36) | |
| renderer.js | 16.82% | (18 / 107) | 0% | (0 / 50) | 0% | (0 / 5) | 16.82% | (18 / 107) | |
| update-manager.js | 28.21% | (11 / 39) | 0% | (0 / 10) | 0% | (0 / 5) | 28.21% | (11 / 39) | |
| util-browser.js | 13.85% | (9 / 65) | 3.57% | (1 / 28) | 0% | (0 / 9) | 13.85% | (9 / 65) | |
| util.js | 32% | (8 / 25) | 0% | (0 / 14) | 0% | (0 / 3) | 32% | (8 / 25) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 1 1 1 1 1 1 | 'use strict';
/* jshint newcap:false */
var domInsert = require('../runtime/dom-insert');
var marko = require('../');
var componentsUtil = require('./util');
var componentLookup = componentsUtil.$__componentLookup;
var emitLifecycleEvent = componentsUtil.$__emitLifecycleEvent;
var destroyComponentForEl = componentsUtil.$__destroyComponentForEl;
var destroyElRecursive = componentsUtil.$__destroyElRecursive;
var getElementById = componentsUtil.$__getElementById;
var EventEmitter = require('events-light');
var RenderResult = require('../runtime/RenderResult');
var SubscriptionTracker = require('listener-tracker');
var inherit = require('raptor-util/inherit');
var updateManager = require('./update-manager');
var morphdom = require('../morphdom');
var eventDelegation = require('./event-delegation');
var slice = Array.prototype.slice;
var MORPHDOM_SKIP = true;
var COMPONENT_SUBSCRIBE_TO_OPTIONS;
var NON_COMPONENT_SUBSCRIBE_TO_OPTIONS = {
addDestroyListener: false
};
var emit = EventEmitter.prototype.emit;
function removeListener(removeEventListenerHandle) {
removeEventListenerHandle();
}
function checkCompatibleComponent(globalComponentsContext, el) {
var component = el._w;
while(component) {
var id = component.id;
var newComponentDef = globalComponentsContext.$__componentsById[id];
if (newComponentDef && component.$__type == newComponentDef.$__component.$__type) {
break;
}
var rootFor = component.$__rootFor;
if (rootFor) {
component = rootFor;
} else {
component.$__destroyShallow();
break;
}
}
}
function handleCustomEventWithMethodListener(component, targetMethodName, args, extraArgs) {
// Remove the "eventType" argument
args.push(component);
if (extraArgs) {
args = extraArgs.concat(args);
}
var targetComponent = componentLookup[component.$__scope];
var targetMethod = targetComponent[targetMethodName];
if (!targetMethod) {
throw Error('Method not found: ' + targetMethodName);
}
targetMethod.apply(targetComponent, args);
}
function getElIdHelper(component, componentElId, index) {
var id = component.id;
var elId = componentElId != null ? id + '-' + componentElId : id;
if (index != null) {
elId += '[' + index + ']';
}
return elId;
}
/**
* This method is used to process "update_<stateName>" handler functions.
* If all of the modified state properties have a user provided update handler
* then a rerender will be bypassed and, instead, the DOM will be updated
* looping over and invoking the custom update handlers.
* @return {boolean} Returns true if if the DOM was updated. False, otherwise.
*/
function processUpdateHandlers(component, stateChanges, oldState) {
var handlerMethod;
var handlers;
for (var propName in stateChanges) {
if (stateChanges.hasOwnProperty(propName)) {
var handlerMethodName = 'update_' + propName;
handlerMethod = component[handlerMethodName];
if (handlerMethod) {
(handlers || (handlers=[])).push([propName, handlerMethod]);
} else {
// This state change does not have a state handler so return false
// to force a rerender
return;
}
}
}
// If we got here then all of the changed state properties have
// an update handler or there are no state properties that actually
// changed.
if (handlers) {
// Otherwise, there are handlers for all of the changed properties
// so apply the updates using those handlers
handlers.forEach(function(handler, i) {
var propertyName = handler[0];
handlerMethod = handler[1];
var newValue = stateChanges[propertyName];
var oldValue = oldState[propertyName];
handlerMethod.call(component, newValue, oldValue);
});
emitLifecycleEvent(component, 'update');
component.$__reset();
}
return true;
}
function checkInputChanged(existingComponent, oldInput, newInput) {
if (oldInput != newInput) {
if (oldInput == null || newInput == null) {
return true;
}
var oldKeys = Object.keys(oldInput);
var newKeys = Object.keys(newInput);
var len = oldKeys.length;
if (len !== newKeys.length) {
return true;
}
for (var i=0; i<len; i++) {
var key = oldKeys[i];
if (oldInput[key] !== newInput[key]) {
return true;
}
}
}
return false;
}
function onNodeDiscarded(node) {
if (node.nodeType === 1) {
destroyComponentForEl(node);
}
}
function onBeforeNodeDiscarded(node) {
return eventDelegation.$__handleNodeDetach(node);
}
function onBeforeElUpdated(fromEl, key, globalComponentsContext) {
if (key) {
var preserved = globalComponentsContext.$__preserved[key];
if (preserved === true) {
// Don't morph elements that are associated with components that are being
// reused or elements that are being preserved. For components being reused,
// the morphing will take place when the reused component updates.
return MORPHDOM_SKIP;
} else {
// We may need to destroy a Component associated with the current element
// if a new UI component was rendered to the same element and the types
// do not match
checkCompatibleComponent(globalComponentsContext, fromEl);
}
}
}
function onBeforeElChildrenUpdated(el, key, globalComponentsContext) {
if (key) {
var preserved = globalComponentsContext.$__preservedBodies[key];
if (preserved === true) {
// Don't morph the children since they are preserved
return MORPHDOM_SKIP;
}
}
}
function onNodeAdded(node, globalComponentsContext) {
eventDelegation.$__handleNodeAttach(node, globalComponentsContext.$__out);
}
var componentProto;
/**
* Base component type.
*
* NOTE: Any methods that are prefixed with an underscore should be considered private!
*/
function Component(id) {
EventEmitter.call(this);
this.id = id;
this.el = null;
this.$__state = null;
this.$__roots = null;
this.$__subscriptions = null;
this.$__domEventListenerHandles = null;
this.$__bubblingDomEvents = null;
this.$__customEvents = null;
this.$__scope = null;
this.$__renderInput = null;
this.$__input = undefined;
this.$__destroyed = false;
this.$__updateQueued = false;
this.$__dirty = false;
this.$__settingInput = false;
this.$__document = undefined;
}
Component.prototype = componentProto = {
$__isComponent: true,
subscribeTo: function(target) {
if (!target) {
throw TypeError();
}
var subscriptions = this.$__subscriptions || (this.$__subscriptions = new SubscriptionTracker());
var subscribeToOptions = target.$__isComponent ?
COMPONENT_SUBSCRIBE_TO_OPTIONS :
NON_COMPONENT_SUBSCRIBE_TO_OPTIONS;
return subscriptions.subscribeTo(target, subscribeToOptions);
},
emit: function(eventType) {
var customEvents = this.$__customEvents;
var target;
if (customEvents && (target = customEvents[eventType])) {
var targetMethodName = target[0];
var extraArgs = target[1];
var args = slice.call(arguments, 1);
handleCustomEventWithMethodListener(this, targetMethodName, args, extraArgs);
}
if (this.listenerCount(eventType)) {
return emit.apply(this, arguments);
}
},
getElId: function (componentElId, index) {
return getElIdHelper(this, componentElId, index);
},
getEl: function (componentElId, index) {
var doc = this.$__document;
if (componentElId != null) {
return getElementById(doc, getElIdHelper(this, componentElId, index));
} else {
return this.el || getElementById(doc, getElIdHelper(this));
}
},
getEls: function(id) {
var els = [];
var i = 0;
var el;
while((el = this.getEl(id, i))) {
els.push(el);
i++;
}
return els;
},
getComponent: function(id, index) {
return componentLookup[getElIdHelper(this, id, index)];
},
getComponents: function(id) {
var components = [];
var i = 0;
var component;
while((component = componentLookup[getElIdHelper(this, id, i)])) {
components.push(component);
i++;
}
return components;
},
destroy: function() {
if (this.$__destroyed) {
return;
}
var els = this.els;
this.$__destroyShallow();
var rootComponents = this.$__rootComponents;
if (rootComponents) {
rootComponents.forEach(function(rootComponent) {
rootComponent.$__destroy();
});
}
els.forEach(function(el) {
destroyElRecursive(el);
var parentNode = el.parentNode;
if (parentNode) {
parentNode.removeChild(el);
}
});
},
$__destroyShallow: function() {
if (this.$__destroyed) {
return;
}
emitLifecycleEvent(this, 'destroy');
this.$__destroyed = true;
this.el = null;
// Unsubscribe from all DOM events
this.$__removeDOMEventListeners();
var subscriptions = this.$__subscriptions;
if (subscriptions) {
subscriptions.removeAllListeners();
this.$__subscriptions = null;
}
delete componentLookup[this.id];
},
isDestroyed: function() {
return this.$__destroyed;
},
get state() {
return this.$__state;
},
set state(newState) {
var state = this.$__state;
if (!state && !newState) {
return;
}
if (!state) {
state = this.$__state = new this.$__State(this);
}
state.$__replace(newState || {});
if (state.$__dirty) {
this.$__queueUpdate();
}
if (!newState) {
this.$__state = null;
}
},
setState: function(name, value) {
var state = this.$__state;
if (typeof name == 'object') {
// Merge in the new state with the old state
var newState = name;
for (var k in newState) {
if (newState.hasOwnProperty(k)) {
state.$__set(k, newState[k], true /* ensure:true */);
}
}
} else {
state.$__set(name, value, true /* ensure:true */);
}
},
setStateDirty: function(name, value) {
var state = this.$__state;
if (arguments.length == 1) {
value = state[name];
}
state.$__set(name, value, true /* ensure:true */, true /* forceDirty:true */);
},
replaceState: function(newState) {
this.$__state.$__replace(newState);
},
get input() {
return this.$__input;
},
set input(newInput) {
if (this.$__settingInput) {
this.$__input = newInput;
} else {
this.$__setInput(newInput);
}
},
$__setInput: function(newInput, onInput, out) {
onInput = onInput || this.onInput;
var updatedInput;
var oldInput = this.$__input;
this.$__input = undefined;
if (onInput) {
// We need to set a flag to preview `this.input = foo` inside
// onInput causing infinite recursion
this.$__settingInput = true;
updatedInput = onInput.call(this, newInput || {}, out);
this.$__settingInput = false;
}
newInput = this.$__renderInput = updatedInput || newInput;
if ((this.$__dirty = checkInputChanged(this, oldInput, newInput))) {
this.$__queueUpdate();
}
if (this.$__input === undefined) {
this.$__input = newInput;
}
return newInput;
},
forceUpdate: function() {
this.$__dirty = true;
this.$__queueUpdate();
},
$__queueUpdate: function() {
if (!this.$__updateQueued) {
updateManager.$__queueComponentUpdate(this);
}
},
update: function() {
if (this.$__destroyed === true || this.$__isDirty === false) {
return;
}
var input = this.$__input;
var state = this.$__state;
if (this.$__dirty === false && state !== null && state.$__dirty === true) {
if (processUpdateHandlers(this, state.$__changes, state.$__old, state)) {
state.$__dirty = false;
}
}
if (this.$__isDirty === true) {
// The UI component is still dirty after process state handlers
// then we should rerender
if (this.shouldUpdate(input, state) !== false) {
this.$__rerender();
}
}
this.$__reset();
},
get $__isDirty() {
return this.$__dirty === true || (this.$__state !== null && this.$__state.$__dirty === true);
},
$__reset: function() {
this.$__dirty = false;
this.$__updateQueued = false;
this.$__renderInput = null;
var state = this.$__state;
if (state) {
state.$__reset();
}
},
shouldUpdate: function(newState, newProps) {
return true;
},
$__emitLifecycleEvent: function(eventType, eventArg1, eventArg2) {
emitLifecycleEvent(this, eventType, eventArg1, eventArg2);
},
$__rerender: function(input) {
if (input) {
this.input = input;
}
var self = this;
var renderer = self.$__renderer;
if (!renderer) {
throw TypeError();
}
var globalData = {
$w: self
};
var fromEls = self.$__getRootEls({});
var doc = self.$__document;
input = this.$__renderInput || this.$__input;
updateManager.$__batchUpdate(function() {
var createOut = renderer.createOut || marko.createOut;
var out = createOut(globalData);
out.sync();
out.$__document = self.$__document;
renderer(input, out);
var result = new RenderResult(out);
var targetNode = out.$__getOutput();
var globalComponentsContext = out.global.components;
var fromEl;
var targetEl = targetNode.firstChild;
while(targetEl) {
var id = targetEl.id;
if (id) {
fromEl = fromEls[id];
if (fromEl) {
morphdom(
fromEl,
targetEl,
globalComponentsContext,
onNodeAdded,
onBeforeElUpdated,
onBeforeNodeDiscarded,
onNodeDiscarded,
onBeforeElChildrenUpdated);
}
}
targetEl = targetEl.nextSibling;
}
result.afterInsert(doc);
out.emit('$__componentsInitialized');
});
this.$__reset();
},
$__getRootEls: function(rootEls) {
var i, len;
var componentEls = this.els;
for (i=0, len=componentEls.length; i<len; i++) {
var componentEl = componentEls[i];
rootEls[componentEl.id] = componentEl;
}
var rootComponents = this.$__rootComponents;
if (rootComponents) {
for (i=0, len=rootComponents.length; i<len; i++) {
var rootComponent = rootComponents[i];
rootComponent.$__getRootEls(rootEls);
}
}
return rootEls;
},
$__removeDOMEventListeners: function() {
var eventListenerHandles = this.$__domEventListenerHandles;
if (eventListenerHandles) {
eventListenerHandles.forEach(removeListener);
this.$__domEventListenerHandles = null;
}
},
get $__rawState() {
var state = this.$__state;
return state && state.$__raw;
},
$__setCustomEvents: function(customEvents, scope) {
var finalCustomEvents = this.$__customEvents = {};
this.$__scope = scope;
customEvents.forEach(function(customEvent) {
var eventType = customEvent[0];
var targetMethodName = customEvent[1];
var extraArgs = customEvent[2];
finalCustomEvents[eventType] = [targetMethodName, extraArgs];
});
}
};
componentProto.elId = componentProto.getElId;
componentProto.$__update = componentProto.update;
componentProto.$__destroy = componentProto.destroy;
// Add all of the following DOM methods to Component.prototype:
// - appendTo(referenceEl)
// - replace(referenceEl)
// - replaceChildrenOf(referenceEl)
// - insertBefore(referenceEl)
// - insertAfter(referenceEl)
// - prependTo(referenceEl)
domInsert(
componentProto,
function getEl(component) {
var els = this.els;
var elCount = els.length;
if (elCount > 1) {
var fragment = component.$__document.createDocumentFragment();
els.forEach(function(el) {
fragment.appendChild(el);
});
return fragment;
} else {
return els[0];
}
},
function afterInsert(component) {
return component;
});
inherit(Component, EventEmitter);
module.exports = Component;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var nextRepeatedId = require('./nextRepeatedId');
var repeatedRegExp = /\[\]$/;
var componentUtil = require('./util');
var nextComponentId = componentUtil.$__nextComponentId;
var attachBubblingEvent = componentUtil.$__attachBubblingEvent;
var extend = require('raptor-util/extend');
var registry = require('./registry');
/**
* A ComponentDef is used to hold the metadata collected at runtime for
* a single component and this information is used to instantiate the component
* later (after the rendered HTML has been added to the DOM)
*/
function ComponentDef(component, componentId, out, componentStack, componentStackLen) {
this.$__out = out; // The AsyncWriter that this component is associated with
this.$__componentStack = componentStack;
this.$__componentStackLen = componentStackLen;
this.$__component = component;
this.id = componentId;
this.$__roots = null; // IDs of root elements if there are multiple root elements
this.$__children = null; // An array of nested ComponentDef instances
this.$__domEvents = null; // An array of DOM events that need to be added (in sets of three)
this.$__bubblingDomEvents = null; // Used to keep track of bubbling DOM events for components rendered on the server
this.$__isExisting = false;
this.$__nextIdIndex = 0; // The unique integer to use for the next scoped ID
}
ComponentDef.prototype = {
$__end: function() {
this.$__componentStack.length = this.$__componentStackLen;
},
/**
* Register a nested component for this component. We maintain a tree of components
* so that we can instantiate nested components before their parents.
*/
$__addChild: function (componentDef) {
var children = this.$__children;
if (children) {
children.push(componentDef);
} else {
this.$__children = [componentDef];
}
},
/**
* This helper method generates a unique and fully qualified DOM element ID
* that is unique within the scope of the current component. This method prefixes
* the the nestedId with the ID of the current component. If nestedId ends
* with `[]` then it is treated as a repeated ID and we will generate
* an ID with the current index for the current nestedId.
* (e.g. "myParentId-foo[0]", "myParentId-foo[1]", etc.)
*/
elId: function (nestedId) {
var id = this.id;
if (nestedId == null) {
return id;
} else {
if (typeof nestedId == 'string' && repeatedRegExp.test(nestedId)) {
return nextRepeatedId(this.$__out, id, nestedId);
} else {
return id + '-' + nestedId;
}
}
},
/**
* Registers a DOM event for a nested HTML element associated with the
* component. This is only done for non-bubbling events that require
* direct event listeners to be added.
* @param {String} type The DOM event type ("mouseover", "mousemove", etc.)
* @param {String} targetMethod The name of the method to invoke on the scoped component
* @param {String} elId The DOM element ID of the DOM element that the event listener needs to be added too
*/
e: function(type, targetMethod, elId, extraArgs) {
if (targetMethod) {
// The event handler method is allowed to be conditional. At render time if the target
// method is null then we do not attach any direct event listeners.
(this.$__domEvents || (this.$__domEvents = [])).push([
type,
targetMethod,
elId,
extraArgs]);
}
},
/**
* Returns the next auto generated unique ID for a nested DOM element or nested DOM component
*/
$__nextId: function() {
var id = this.id;
return id ?
id + '-c' + (this.$__nextIdIndex++) :
nextComponentId(this.$__out);
},
d: function(handlerMethodName, extraArgs) {
return attachBubblingEvent(this, handlerMethodName, extraArgs);
}
};
ComponentDef.$__deserialize = function(o, types) {
var id = o[0];
var typeName = types[o[1]];
var input = o[2];
var extra = o[3];
var state = extra.s;
var componentProps = extra.w;
var component = typeName /* legacy */ && registry.$__createComponent(typeName, id);
if (extra.b) {
component.$__bubblingDomEvents = extra.b;
}
// Preview newly created component from being queued for update since we area
// just building it from the server info
component.$__updateQueued = true;
if (state) {
var undefinedPropNames = extra.u;
if (undefinedPropNames) {
undefinedPropNames.forEach(function(undefinedPropName) {
state[undefinedPropName] = undefined;
});
}
// We go through the setter here so that we convert the state object
// to an instance of `State`
component.state = state;
}
component.$__input = input;
if (componentProps) {
extend(component, componentProps);
}
var scope = extra.p;
var customEvents = extra.e;
if (customEvents) {
component.$__setCustomEvents(customEvents, scope);
}
return {
$__component: component,
$__roots: extra.r,
$__domEvents: extra.d
};
};
module.exports = ComponentDef;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var ComponentDef = require('./ComponentDef');
var initComponents = require('./init-components');
var EMPTY_OBJECT = {};
function GlobalComponentsContext(out) {
this.$__roots = [];
this.$__preserved = EMPTY_OBJECT;
this.$__preservedBodies = EMPTY_OBJECT;
this.$__componentsById = {};
this.$__out = out;
}
GlobalComponentsContext.prototype = {
$__initComponents: function (doc) {
var topLevelComponentDefs = null;
this.$__roots.forEach(function(root) {
var children = root.$__children;
if (children) {
initComponents.$__initClientRendered(children, doc);
if (topLevelComponentDefs === null) {
topLevelComponentDefs = children;
} else {
topLevelComponentDefs = topLevelComponentDefs.concat(children);
}
}
});
this.$__roots = null;
return topLevelComponentDefs;
},
$__preserveDOMNode: function(elId, bodyOnly) {
var preserved = bodyOnly === true ? this.$__preservedBodies : this.$__preserved;
if (preserved === EMPTY_OBJECT) {
if (bodyOnly === true) {
preserved = this.$__preservedBodies = {};
} else {
preserved = this.$__preserved = {};
}
}
preserved[elId] = true;
}
};
function ComponentsContext(out, parentComponentsContext, shouldAddGlobalRoot) {
var root;
var globalComponentsContext;
if (parentComponentsContext === undefined) {
root = new ComponentDef(null, null, out);
globalComponentsContext = out.global.components;
if (globalComponentsContext === undefined) {
out.global.components = globalComponentsContext = new GlobalComponentsContext(out);
}
if (shouldAddGlobalRoot !== false) {
globalComponentsContext.$__roots.push(root);
}
} else {
globalComponentsContext = parentComponentsContext.$__globalContext;
var parentComponentStack = parentComponentsContext.$__componentStack;
root = parentComponentStack[parentComponentStack.length-1];
}
this.$__globalContext = globalComponentsContext;
this.$__out = out;
this.$__componentStack = [root];
}
ComponentsContext.prototype = {
$__createNestedComponentsContext: function(nestedOut) {
return new ComponentsContext(nestedOut, this);
},
$__beginComponent: function(component) {
var componentStack = this.$__componentStack;
var origLength = componentStack.length;
var parent = componentStack[origLength - 1];
var componentId = component.id;
if (!componentId) {
componentId = component.id = parent.$__nextId();
}
var componentDef = new ComponentDef(component, componentId, this.$__out, componentStack, origLength);
this.$__globalContext.$__componentsById[componentId] = componentDef;
parent.$__addChild(componentDef);
componentStack.push(componentDef);
return componentDef;
},
$__nextComponentId: function() {
var componentStack = this.$__componentStack;
var parent = componentStack[componentStack.length - 1];
return parent.$__nextId();
}
};
function getComponentsContext(out) {
return out.data.components || (out.data.components = new ComponentsContext(out));
}
module.exports = exports = ComponentsContext;
exports.$__getComponentsContext = getComponentsContext;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | 1 1 1 1 1 | var extend = require('raptor-util/extend');
function ensure(state, propertyName) {
var proto = state.constructor.prototype;
if (!(propertyName in proto)) {
Object.defineProperty(proto, propertyName, {
get: function() {
return this.$__raw[propertyName];
},
set: function(value) {
this.$__set(propertyName, value, false /* ensure:false */);
}
});
}
}
function State(component) {
this.$__component = component;
this.$__raw = {};
this.$__dirty = false;
this.$__old = null;
this.$__changes = null;
this.$__forced = null; // An object that we use to keep tracking of state properties that were forced to be dirty
Object.seal(this);
}
State.prototype = {
$__reset: function() {
var self = this;
self.$__dirty = false;
self.$__old = null;
self.$__changes = null;
self.$__forced = null;
},
$__replace: function(newState) {
var state = this;
var key;
var rawState = this.$__raw;
for (key in rawState) {
if (!(key in newState)) {
state.$__set(key, undefined, false /* ensure:false */, false /* forceDirty:false */);
}
}
for (key in newState) {
state.$__set(key, newState[key], true /* ensure:true */, false /* forceDirty:false */);
}
},
$__set: function(name, value, shouldEnsure, forceDirty) {
var rawState = this.$__raw;
if (shouldEnsure) {
ensure(this, name);
}
if (forceDirty) {
var forcedDirtyState = this.$__forced || (this.$__forced = {});
forcedDirtyState[name] = true;
} else if (rawState[name] === value) {
return;
}
if (!this.$__dirty) {
// This is the first time we are modifying the component state
// so introduce some properties to do some tracking of
// changes to the state
this.$__dirty = true; // Mark the component state as dirty (i.e. modified)
this.$__old = rawState;
this.$__raw = rawState = extend({}, rawState);
this.$__changes = {};
this.$__component.$__queueUpdate();
}
this.$__changes[name] = value;
if (value === undefined) {
// Don't store state properties with an undefined or null value
delete rawState[name];
} else {
// Otherwise, store the new value in the component state
rawState[name] = value;
}
},
toJSON: function() {
return this.$__raw;
}
};
module.exports = State;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | 1 1 1 1 1 1 1 1 1 1 | var eventDelegation = require('./event-delegation');
var delegateEvent = eventDelegation.$__delegateEvent;
var getEventFromEl = eventDelegation.$__getEventFromEl;
var componentsUtil = require('./util');
var destroyElRecursive = componentsUtil.$__destroyElRecursive;
var destroyComponentForEl = componentsUtil.$__destroyComponentForEl;
function handleNodeAttach(node, out) {
if (node.nodeType === 1) {
var target = getEventFromEl(node, 'onattach');
if (target) {
var data = out.data;
var attachTargets = data.$__attachTargets;
if (!attachTargets) {
attachTargets = data.$__attachTargets = [];
out.on('$__componentsInitialized', function() {
for (var i=0; i<attachTargets.length; i+=2) {
var node = attachTargets[i];
var target = attachTargets[i+1];
delegateEvent(node, target, {});
}
});
}
attachTargets.push(node);
attachTargets.push(target);
}
}
}
function handleNodeDetach(node) {
if (node.nodeType === 1) {
var target = getEventFromEl(node, 'ondetach');
if (target) {
var allowDetach;
delegateEvent(node, target, {
preventDefault: function() {
allowDetach = false;
destroyComponentForEl(node);
destroyElRecursive(node);
},
detach: function() {
var parentNode = node.parentNode;
if (parentNode) {
parentNode.removeChild(node);
}
}
});
return allowDetach;
}
}
}
eventDelegation.$__handleNodeAttach = handleNodeAttach;
eventDelegation.$__handleNodeDetach = handleNodeDetach;
|
| 1 2 | 2 | require('./init-components').$__initServerRendered();
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 1 | module.exports = [
/* Mouse Events */
'click',
'dblclick',
'mousedown',
'mouseup',
// 'mouseover',
// 'mousemove',
// 'mouseout',
'dragstart',
'drag',
// 'dragenter',
// 'dragleave',
// 'dragover',
'drop',
'dragend',
/* Keyboard Events */
'keydown',
'keypress',
'keyup',
/* Form Events */
'select',
'change',
'submit',
'reset',
'input',
'attach', // Pseudo event supported by Marko
'detach' // Pseudo event supported by Marko
// 'focus', <-- Does not bubble
// 'blur', <-- Does not bubble
// 'focusin', <-- Not supported in all browsers
// 'focusout' <-- Not supported in all browsers
];
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | 1 1 1 1 1 1 | 'use strict';
/* jshint newcap:false */
var BaseState = require('./State');
var BaseComponent = require('./Component');
var inherit = require('raptor-util/inherit');
module.exports = function defineComponent(def, renderer) {
if (def.$__isComponent) {
return def;
}
var ComponentClass = function() {};
var proto;
var type = typeof def;
if (type == 'function') {
proto = def.prototype;
} else if (type == 'object') {
proto = def;
} else {
throw TypeError();
}
ComponentClass.prototype = proto;
// We don't use the constructor provided by the user
// since we don't invoke their constructor until
// we have had a chance to do our own initialization.
// Instead, we store their constructor in the "initComponent"
// property and that method gets called later inside
// init-components-browser.js
function Component(id) {
BaseComponent.call(this, id);
}
if (!proto.$__isComponent) {
// Inherit from Component if they didn't already
inherit(ComponentClass, BaseComponent);
}
// The same prototype will be used by our constructor after
// we he have set up the prototype chain using the inherit function
proto = Component.prototype = ComponentClass.prototype;
// proto.constructor = def.constructor = Component;
// Set a flag on the constructor function to make it clear this is
// a component so that we can short-circuit this work later
Component.$__isComponent = true;
function State(component) { BaseState.call(this, component); }
inherit(State, BaseState);
proto.$__State = State;
proto.$__renderer = renderer;
return Component;
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | var componentsUtil = require('./util');
var runtimeId = componentsUtil.$__runtimeId;
var componentLookup = componentsUtil.$__componentLookup;
var getMarkoPropsFromEl = componentsUtil.$__getMarkoPropsFromEl;
var isArray = Array.isArray;
// We make our best effort to allow multiple marko runtimes to be loaded in the
// same window. Each marko runtime will get its own unique runtime ID.
var listenersAttachedKey = '$MED' + runtimeId;
function getEventFromEl(el, eventName) {
var virtualProps = getMarkoPropsFromEl(el);
var eventInfo = virtualProps[eventName];
if (typeof eventInfo === 'string') {
eventInfo = eventInfo.split(' ');
if (eventInfo.length == 3) {
eventInfo[2] = parseInt(eventInfo[2], 10);
}
}
return eventInfo;
}
function delegateEvent(node, target, event) {
var targetMethod = target[0];
var targetComponentId = target[1];
var extraArgs = target[2];
var targetComponent = componentLookup[targetComponentId];
if (!targetComponent) {
return;
}
var targetFunc = targetComponent[targetMethod];
if (!targetFunc) {
throw Error('Method not found: ' + targetMethod);
}
if (extraArgs != null) {
if (typeof extraArgs === 'number') {
extraArgs = targetComponent.$__bubblingDomEvents[extraArgs];
if (!isArray(extraArgs)) {
extraArgs = [extraArgs];
}
}
}
// Invoke the component method
if (extraArgs) {
targetFunc.apply(targetComponent, extraArgs.concat(event, node));
} else {
targetFunc.call(targetComponent, event, node);
}
}
function attachBubbleEventListeners(doc) {
var body = doc.body;
// Here's where we handle event delegation using our own mechanism
// for delegating events. For each event that we have white-listed
// as supporting bubble, we will attach a listener to the root
// document.body element. When we get notified of a triggered event,
// we again walk up the tree starting at the target associated
// with the event to find any mappings for event. Each mapping
// is from a DOM event type to a method of a component.
require('./bubble').forEach(function addBubbleHandler(eventType) {
body.addEventListener(eventType, function(event) {
var propagationStopped = false;
// Monkey-patch to fix #97
var oldStopPropagation = event.stopPropagation;
event.stopPropagation = function() {
oldStopPropagation.call(event);
propagationStopped = true;
};
var curNode = event.target;
if (!curNode) {
return;
}
// Search up the tree looking DOM events mapped to target
// component methods
var propName = 'on' + eventType;
var target;
// Attributes will have the following form:
// on<event_type>("<target_method>|<component_id>")
do {
if ((target = getEventFromEl(curNode, propName))) {
delegateEvent(curNode, target, event);
if (propagationStopped) {
break;
}
}
} while((curNode = curNode.parentNode) && curNode.getAttribute);
});
});
}
function noop() {}
exports.$__handleNodeAttach = noop;
exports.$__handleNodeDetach = noop;
exports.$__delegateEvent = delegateEvent;
exports.$__getEventFromEl = getEventFromEl;
exports.$__init = function(doc) {
if (!doc[listenersAttachedKey]) {
doc[listenersAttachedKey] = true;
attachBubbleEventListeners(doc);
}
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 2 2 2 1 2 2 2 2 2 2 2 2 | var componentsUtil = require('./util');
var events = require('../runtime/events');
var Component = require('./Component');
function onInitComponent(listener) {
events.on('initComponent', listener);
}
exports.onInitComponent = onInitComponent;
exports.Component = Component;
exports.getComponentForEl = componentsUtil.$__getComponentForEl;
exports.init = require('./init-components').$__initServerRendered;
exports.c = require('./defineComponent'); // Referenced by compiled templates
exports.r = require('./renderer'); // Referenced by compiled templates
exports.rc = require('./registry').$__register; // Referenced by compiled templates
window.$__MARKO_COMPONENTS = exports; // Helpful when debugging... WARNING: DO NOT USE IN REAL CODE!
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var warp10 = require('warp10');
var escapeEndingScriptTagRegExp = /<\//g;
function flattenHelper(components, flattened, typesArray, typesLookup) {
for (var i = 0, len = components.length; i < len; i++) {
var componentDef = components[i];
var id = componentDef.id;
var component = componentDef.$__component;
var state = component.state;
var input = component.input;
var typeName = component.typeName;
var customEvents = component.$__customEvents;
var scope = component.$__scope;
component.state = undefined; // We don't use `delete` to avoid V8 deoptimization
component.input = undefined; // We don't use `delete` to avoid V8 deoptimization
component.typeName = undefined;
component.id = undefined;
component.$__customEvents = undefined;
component.$__scope = undefined;
if (!typeName) {
continue;
}
var typeIndex = typesLookup[typeName];
if (typeIndex === undefined) {
typeIndex = typesArray.length;
typesArray.push(typeName);
typesLookup[typeName] = typeIndex;
}
var children = componentDef.$__children;
if (children !== null) {
// Depth-first search (children should be initialized before parent)
flattenHelper(children, flattened, typesArray, typesLookup);
componentDef.$__children = null;
}
var hasProps = false;
for (var key in component) {
if (component.hasOwnProperty(key) && component[key] !== undefined) {
hasProps = true;
}
}
var undefinedPropNames;
if (state) {
// Update state properties with an `undefined` value to have a `null`
// value so that the property name will be serialized down to the browser.
// This ensures that we add the proper getter/setter for the state property.
for (var k in state) {
if (state[k] === undefined) {
if (undefinedPropNames) {
undefinedPropNames.push(k);
} else {
undefinedPropNames = [k];
}
}
}
}
var extra = {
p: customEvents && scope, // Only serialize scope if we need to attach custom events
d: componentDef.$__domEvents,
b: componentDef.$__bubblingDomEvents,
e: customEvents,
w: hasProps ? component : undefined,
s: state,
r: componentDef.$__roots,
u: undefinedPropNames
};
flattened.push([
id, // 0 = id
typeIndex, // 1 = type
input, // 2 = input
extra // 3
]);
}
}
function getRenderedComponents(out, shouldIncludeAll) {
var componentDefs;
var globalComponentsContext;
if (shouldIncludeAll === true) {
globalComponentsContext = out.global.components;
if (globalComponentsContext === undefined) {
return undefined;
}
} else {
let componentsContext = out.data.components;
if (componentsContext === undefined) {
return undefined;
}
let rootComponentDef = componentsContext.$__componentStack[0];
componentDefs = rootComponentDef.$__children;
if (componentDefs === null) {
return undefined;
}
rootComponentDef.$__children = null;
}
var flattened = [];
var typesLookup = {};
var typesArray = [];
if (shouldIncludeAll === true) {
let roots = globalComponentsContext.$__roots;
for (let i=0, len=roots.length; i<len; i++) {
let root = roots[i];
let children = root.$__children;
if (children !== null) {
flattenHelper(children, flattened, typesArray, typesLookup);
}
}
} else {
flattenHelper(componentDefs, flattened, typesArray, typesLookup);
}
if (flattened.length === 0) {
return undefined;
}
return {w: flattened, t: typesArray};
}
function writeInitComponentsCode(out, shouldIncludeAll) {
var renderedComponents = getRenderedComponents(out, shouldIncludeAll);
if (renderedComponents === undefined) {
return;
}
var cspNonce = out.global.cspNonce;
var nonceAttr = cspNonce ? ' nonce='+JSON.stringify(cspNonce) : '';
out.write('<script' + nonceAttr + '>' +
'(function(){var w=window;w.$components=(w.$components||[]).concat(' +
warp10.stringify(renderedComponents).replace(escapeEndingScriptTagRegExp, '\\u003C/') +
')||w.$components})()</script>');
}
exports.writeInitComponentsCode = writeInitComponentsCode;
/**
* Returns an object that can be sent to the browser using JSON.stringify. The parsed object should be
* passed to require('marko-components').initComponents(...);
*
* @param {ComponentsContext|AsyncWriter} componentsContext A ComponentsContext or an AsyncWriter
* @return {Object} An object with information about the rendered components that can be serialized to JSON. The object should be treated as opaque
*/
exports.getRenderedComponents = function(out) {
var renderedComponents = getRenderedComponents(out, true);
return warp10.stringifyPrepare(renderedComponents);
};
exports.r = require('./renderer');
exports.c = function() { /* no op for defining a component on teh server */ };
// registerComponent is a no-op on the server.
// Fixes https://github.com/marko-js/marko-components/issues/111
exports.rc = function(typeName) { return typeName; };
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | 2 2 2 1 1 1 1 1 1 | 'use strict';
var warp10Finalize = require('warp10/finalize');
var eventDelegation = require('./event-delegation');
var win = window;
var defaultDocument = document;
var events = require('../runtime/events');
var componentsUtil = require('./util');
var componentLookup = componentsUtil.$__componentLookup;
var getElementById = componentsUtil.$__getElementById;
var ComponentDef = require('./ComponentDef');
function invokeComponentEventHandler(component, targetMethodName, args) {
var method = component[targetMethodName];
if (!method) {
throw Error('Method not found: ' + targetMethodName);
}
method.apply(component, args);
}
function addEventListenerHelper(el, eventType, listener) {
el.addEventListener(eventType, listener, false);
return function remove() {
el.removeEventListener(eventType, listener);
};
}
function addDOMEventListeners(component, el, eventType, targetMethodName, extraArgs, handles) {
var removeListener = addEventListenerHelper(el, eventType, function(event) {
var args = [event, el];
if (extraArgs) {
args = extraArgs.concat(args);
}
invokeComponentEventHandler(component, targetMethodName, args);
});
handles.push(removeListener);
}
function initComponent(componentDef, doc) {
var component = componentDef.$__component;
if (!component || !component.$__isComponent) {
return; // legacy
}
var domEvents = componentDef.$__domEvents;
component.$__reset();
component.$__document = doc;
var isExisting = componentDef.$__isExisting;
var id = component.id;
var rootIds = componentDef.$__roots;
if (rootIds) {
var rootComponents;
var els = [];
rootIds.forEach(function(rootId) {
var nestedId = id + '-' + rootId;
var rootComponent = componentLookup[nestedId];
if (rootComponent) {
rootComponent.$__rootFor = component;
if (rootComponents) {
rootComponents.push(rootComponent);
} else {
rootComponents = component.$__rootComponents = [rootComponent];
}
} else {
var rootEl = getElementById(doc, nestedId);
if (rootEl) {
rootEl._w = component;
els.push(rootEl);
}
}
});
component.el = els[0];
component.els = els;
componentLookup[id] = component;
} else if (!isExisting) {
var el = getElementById(doc, id);
el._w = component;
component.el = el;
component.els = [el];
componentLookup[id] = component;
}
if (isExisting) {
component.$__removeDOMEventListeners();
}
if (domEvents) {
var eventListenerHandles = [];
domEvents.forEach(function(domEventArgs) {
// The event mapping is for a direct DOM event (not a custom event and not for bubblign dom events)
var eventType = domEventArgs[0];
var targetMethodName = domEventArgs[1];
var eventEl = getElementById(doc, domEventArgs[2]);
var extraArgs = domEventArgs[3];
addDOMEventListeners(component, eventEl, eventType, targetMethodName, extraArgs, eventListenerHandles);
});
if (eventListenerHandles.length) {
component.$__domEventListenerHandles = eventListenerHandles;
}
}
if (isExisting) {
component.$__emitLifecycleEvent('update');
} else {
events.emit('mountComponent', component);
component.$__emitLifecycleEvent('mount');
}
}
/**
* This method is used to initialized components associated with UI components
* rendered in the browser. While rendering UI components a "components context"
* is added to the rendering context to keep up with which components are rendered.
* When ready, the components can then be initialized by walking the component tree
* in the components context (nested components are initialized before ancestor components).
* @param {Array<marko-components/lib/ComponentDef>} componentDefs An array of ComponentDef instances
*/
function initClientRendered(componentDefs, doc) {
// Ensure that event handlers to handle delegating events are
// always attached before initializing any components
eventDelegation.$__init(doc);
doc = doc || defaultDocument;
for (var i=0,len=componentDefs.length; i<len; i++) {
var componentDef = componentDefs[i];
if (componentDef.$__children) {
initClientRendered(componentDef.$__children, doc);
}
initComponent(
componentDef,
doc);
}
}
/**
* This method initializes all components that were rendered on the server by iterating over all
* of the component IDs.
*/
function initServerRendered(renderedComponents, doc) {
if (!renderedComponents) {
renderedComponents = win.$components;
if (renderedComponents) {
if (renderedComponents.forEach) {
renderedComponents.forEach(function(renderedComponent) {
initServerRendered(renderedComponent, doc);
});
}
} else {
win.$components = {
concat: initServerRendered
};
}
return;
}
// Ensure that event handlers to handle delegating events are
// always attached before initializing any components
eventDelegation.$__init(doc || defaultDocument);
renderedComponents = warp10Finalize(renderedComponents);
var componentDefs = renderedComponents.w;
var typesArray = renderedComponents.t;
componentDefs.forEach(function(componentDef) {
componentDef = ComponentDef.$__deserialize(componentDef, typesArray);
initComponent(componentDef, doc || defaultDocument);
});
}
exports.$__initClientRendered = initClientRendered;
exports.$__initServerRendered = initServerRendered;
|
| 1 2 | // The server-side implementation of this module is intentionally empty |
| 1 2 3 4 5 6 7 8 9 | 1 | 'use strict'; module.exports = function load(typeName) { // We make the assumption that the component type name is a path to a // fully resolved module path and that the module exists // as a CommonJS module return require(typeName); }; |
| 1 2 3 4 5 | 1 | 'use strict'; module.exports = function load(typeName) { throw new Error('Not found: ' + typeName); }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 1 1 | var REPEATED_ID_KEY = '$rep'; module.exports = function nextRepeatedId(out, parentId, id) { var nextIdLookup = out.global[REPEATED_ID_KEY] || (out.global[REPEATED_ID_KEY] = {}); var indexLookupKey = parentId + '-' + id; var currentIndex = nextIdLookup[indexLookupKey]; if (currentIndex == null) { currentIndex = nextIdLookup[indexLookupKey] = 0; } else { currentIndex = ++nextIdLookup[indexLookupKey]; } return indexLookupKey.slice(0, -2) + '[' + currentIndex + ']'; }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | 1 1 1 1 1 1 1 1 1 1 1 | var loadComponent = require('./loadComponent');
var defineComponent = require('./defineComponent');
var registered = {};
var loaded = {};
var componentTypes = {};
function register(typeName, def) {
// We do this to kick off registering of nested components
// but we don't use the return value just yet since there
// is a good chance that it resulted in a circular dependency
def();
registered[typeName] = def;
delete loaded[typeName];
delete componentTypes[typeName];
return typeName;
}
function load(typeName) {
var target = loaded[typeName];
if (!target) {
target = registered[typeName];
if (target) {
target = target();
} else {
target = loadComponent(typeName); // Assume the typeName has been fully resolved already
}
if (!target) {
throw Error('Not found: ' + typeName);
}
loaded[typeName] = target;
}
return target;
}
function getComponentClass(typeName) {
var ComponentClass = componentTypes[typeName];
if (ComponentClass) {
return ComponentClass;
}
ComponentClass = load(typeName);
ComponentClass = ComponentClass.Component || ComponentClass;
if (!ComponentClass.$__isComponent) {
ComponentClass = defineComponent(ComponentClass, ComponentClass.renderer);
}
// Make the component "type" accessible on each component instance
ComponentClass.prototype.$__type = typeName;
componentTypes[typeName] = ComponentClass;
return ComponentClass;
}
function createComponent(typeName, id) {
var ComponentClass = getComponentClass(typeName);
return new ComponentClass(id);
}
exports.$__register = register;
exports.$__createComponent = createComponent;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | 1 1 1 1 1 1 | 'use strict';
const copyProps = require('raptor-util/copyProps');
const SERVER_WIDGET_KEY = Symbol();
function createServerComponentClass(renderingLogic) {
class ServerComponent {
constructor(id, input, out, typeName, customEvents, scope) {
this.id = id;
this.$__customEvents = customEvents;
this.$__scope = scope;
this.$__updatedInput = undefined;
this.$__input = undefined;
this.$__state = undefined;
this.typeName = typeName;
if (this.onCreate) {
this.onCreate(input, out);
}
if (this.onInput) {
var updatedInput = this.onInput(input, out) || input;
if (this.$__input === undefined) {
this.$__input = updatedInput;
}
this.$__updatedInput = updatedInput;
} else {
this.$__input = this.$__updatedInput = input;
}
if (this.onRender) {
this.onRender(out);
}
}
set input(newInput) {
this.$__input = newInput;
}
get input() {
return this.$__input;
}
set state(newState) {
this.$__state = newState;
}
get state() {
return this.$__state;
}
get $__rawState() {
return this.$__state;
}
}
var renderingLogicProps = typeof renderingLogic === 'function' ?
renderingLogic.prototype :
renderingLogic;
copyProps(renderingLogicProps, ServerComponent.prototype);
return ServerComponent;
}
function createComponent(renderingLogic, id, input, out, typeName, customEvents, scope) {
var ServerComponent = renderingLogic[SERVER_WIDGET_KEY];
if (!ServerComponent) {
ServerComponent = renderingLogic[SERVER_WIDGET_KEY] = createServerComponentClass(renderingLogic);
}
var component = new ServerComponent(id, input, out, typeName, customEvents, scope);
return component;
}
exports.$__isServer = true;
exports.$__createComponent = createComponent;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | var componentsUtil = require('./util');
var componentLookup = componentsUtil.$__componentLookup;
var emitLifecycleEvent = componentsUtil.$__emitLifecycleEvent;
var ComponentsContext = require('./ComponentsContext');
var getComponentsContext = ComponentsContext.$__getComponentsContext;
var nextRepeatedId = require('./nextRepeatedId');
var repeatedRegExp = /\[\]$/;
var registry = require('./registry');
var copyProps = require('raptor-util/copyProps');
var COMPONENT_BEGIN_ASYNC_ADDED_KEY = '$wa';
function resolveComponentKey(out, key, scope) {
if (key[0] == '#') {
return key.substring(1);
} else {
var resolvedId;
if (repeatedRegExp.test(key)) {
resolvedId = nextRepeatedId(out, scope, key);
} else {
resolvedId = scope + '-' + key;
}
return resolvedId;
}
}
function preserveComponentEls(existingComponent, out, componentsContext) {
var rootEls = existingComponent.$__getRootEls({});
for (var elId in rootEls) {
var el = rootEls[elId];
// We put a placeholder element in the output stream to ensure that the existing
// DOM node is matched up correctly when using morphdom.
out.element(el.tagName, { id: elId });
componentsContext.$__globalContext.$__preserveDOMNode(elId); // Mark the element as being preserved (for morphdom)
}
existingComponent.$__reset(); // The component is no longer dirty so reset internal flags
return true;
}
function handleBeginAsync(event) {
var parentOut = event.parentOut;
var asyncOut = event.out;
var componentsContext = parentOut.data.components;
if (componentsContext !== undefined) {
// All of the components in this async block should be
// initialized after the components in the parent. Therefore,
// we will create a new ComponentsContext for the nested
// async block and will create a new component stack where the current
// component in the parent block is the only component in the nested
// stack (to begin with). This will result in top-level components
// of the async block being added as children of the component in the
// parent block.
var nestedComponentsContext = componentsContext.$__createNestedComponentsContext(asyncOut);
asyncOut.data.components = nestedComponentsContext;
}
// Carry along the component arguments
asyncOut.$c = parentOut.$c;
}
function createRendererFunc(templateRenderFunc, componentProps, renderingLogic) {
renderingLogic = renderingLogic || {};
var onInput = renderingLogic.onInput;
var typeName = componentProps.type;
var roots = componentProps.roots;
var assignedId = componentProps.id;
var split = componentProps.split;
return function renderer(input, out) {
var outGlobal = out.global;
if (out.isSync() === false) {
if (!outGlobal[COMPONENT_BEGIN_ASYNC_ADDED_KEY]) {
outGlobal[COMPONENT_BEGIN_ASYNC_ADDED_KEY] = true;
out.on('beginAsync', handleBeginAsync);
}
}
var component = outGlobal.$w;
var isRerender = component !== undefined;
var id = assignedId;
var isExisting;
var customEvents;
var scope;
if (component) {
id = component.id;
isExisting = true;
outGlobal.$w = null;
} else {
var componentArgs = out.$c;
if (componentArgs) {
out.$c = null;
scope = componentArgs[0];
if (scope) {
scope = scope.id;
}
var key = componentArgs[1];
if (key != null) {
key = key.toString();
}
id = id || resolveComponentKey(out, key, scope);
customEvents = componentArgs[2];
}
}
var componentsContext = getComponentsContext(out);
id = id || componentsContext.$__nextComponentId();
if (registry.$__isServer) {
component = registry.$__createComponent(
renderingLogic,
id,
input,
out,
typeName,
customEvents,
scope);
input = component.$__updatedInput;
component.$__updatedInput = undefined; // We don't want $__updatedInput to be serialized to the browser
} else {
if (!component) {
if (isRerender) {
// Look in in the DOM to see if a component with the same ID and type already exists.
component = componentLookup[id];
if (component && component.$__type !== typeName) {
component = undefined;
}
}
if (component) {
isExisting = true;
} else {
isExisting = false;
// We need to create a new instance of the component
component = registry.$__createComponent(typeName, id);
if (split) {
split = false;
var renderingLogicProps = typeof renderingLogic == 'function' ?
renderingLogic.prototype :
renderingLogic;
copyProps(renderingLogicProps, component.constructor.prototype);
}
}
// Set this flag to prevent the component from being queued for update
// based on the new input. The component is about to be rerendered
// so we don't want to queue it up as a result of calling `setInput()`
component.$__updateQueued = true;
if (customEvents !== undefined) {
component.$__setCustomEvents(customEvents, scope);
}
if (isExisting === false) {
emitLifecycleEvent(component, 'create', input, out);
}
input = component.$__setInput(input, onInput, out);
if (isExisting === true) {
if (component.$__isDirty === false || component.shouldUpdate(input, component.$__state) === false) {
preserveComponentEls(component, out, componentsContext);
return;
}
}
}
emitLifecycleEvent(component, 'render', out);
}
var componentDef = componentsContext.$__beginComponent(component);
componentDef.$__roots = roots;
componentDef.$__isExisting = isExisting;
// Render the template associated with the component using the final template
// data that we constructed
templateRenderFunc(input, out, componentDef, component, component.$__rawState);
componentDef.$__end();
};
}
module.exports = createRendererFunc;
// exports used by the legacy renderer
createRendererFunc.$__resolveComponentKey = resolveComponentKey;
createRendererFunc.$__preserveComponentEls = preserveComponentEls;
createRendererFunc.$__handleBeginAsync = handleBeginAsync;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var updatesScheduled = false;
var batchStack = []; // A stack of batched updates
var unbatchedQueue = []; // Used for scheduled batched updates
var nextTick = require('../runtime/nextTick');
/**
* This function is called when we schedule the update of "unbatched"
* updates to components.
*/
function updateUnbatchedComponents() {
if (unbatchedQueue.length) {
try {
updateComponents(unbatchedQueue);
} finally {
// Reset the flag now that this scheduled batch update
// is complete so that we can later schedule another
// batched update if needed
updatesScheduled = false;
}
}
}
function scheduleUpdates() {
if (updatesScheduled) {
// We have already scheduled a batched update for the
// process.nextTick so nothing to do
return;
}
updatesScheduled = true;
nextTick(updateUnbatchedComponents);
}
function updateComponents(queue) {
// Loop over the components in the queue and update them.
// NOTE: It is okay if the queue grows during the iteration
// since we will still get to them at the end
for (var i=0; i<queue.length; i++) {
var component = queue[i];
component.$__update(); // Do the actual component update
}
// Clear out the queue by setting the length to zero
queue.length = 0;
}
function batchUpdate(func) {
// If the batched update stack is empty then this
// is the outer batched update. After the outer
// batched update completes we invoke the "afterUpdate"
// event listeners.
var batch = {
$__queue: null
};
batchStack.push(batch);
try {
func();
} finally {
try {
// Update all of the components that where queued up
// in this batch (if any)
if (batch.$__queue) {
updateComponents(batch.$__queue);
}
} finally {
// Now that we have completed the update of all the components
// in this batch we need to remove it off the top of the stack
batchStack.length--;
}
}
}
function queueComponentUpdate(component) {
var batchStackLen = batchStack.length;
if (batchStackLen) {
// When a batch update is started we push a new batch on to a stack.
// If the stack has a non-zero length then we know that a batch has
// been started so we can just queue the component on the top batch. When
// the batch is ended this component will be updated.
var batch = batchStack[batchStackLen-1];
// We default the batch queue to null to avoid creating an Array instance
// unnecessarily. If it is null then we create a new Array, otherwise
// we push it onto the existing Array queue
if (batch.$__queue) {
batch.$__queue.push(component);
} else {
batch.$__queue = [component];
}
} else {
// We are not within a batched update. We need to schedule a batch update
// for the process.nextTick (if that hasn't been done already) and we will
// add the component to the unbatched queued
scheduleUpdates();
unbatchedQueue.push(component);
}
}
exports.$__queueComponentUpdate = queueComponentUpdate;
exports.$__batchUpdate = batchUpdate;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | 2 1 1 1 1 1 1 1 1 | var markoGlobal = window.$MG || (window.$MG = { uid: 0 }); var runtimeId = markoGlobal.uid++; var componentLookup = {}; var defaultDocument = document; var EMPTY_OBJECT = {}; function getComponentForEl(el, doc) { if (el) { var node = typeof el == 'string' ? (doc || defaultDocument).getElementById(el) : el; if (node) { var component = node._w; while(component) { var rootFor = component.$__rootFor; if (rootFor) { component = rootFor; } else { break; } } return component; } } } var lifecycleEventMethods = {}; [ 'create', 'render', 'update', 'mount', 'destroy', ].forEach(function(eventName) { lifecycleEventMethods[eventName] = 'on' + eventName[0].toUpperCase() + eventName.substring(1); }); /** * This method handles invoking a component's event handler method * (if present) while also emitting the event through * the standard EventEmitter.prototype.emit method. * * Special events and their corresponding handler methods * include the following: * * beforeDestroy --> onBeforeDestroy * destroy --> onDestroy * beforeUpdate --> onBeforeUpdate * update --> onUpdate * render --> onRender */ function emitLifecycleEvent(component, eventType, eventArg1, eventArg2) { var listenerMethod = component[lifecycleEventMethods[eventType]]; if (listenerMethod !== undefined) { listenerMethod.call(component, eventArg1, eventArg2); } component.emit(eventType, eventArg1, eventArg2); } function destroyComponentForEl(el) { var componentToDestroy = el._w; if (componentToDestroy) { componentToDestroy.$__destroyShallow(); el._w = null; while ((componentToDestroy = componentToDestroy.$__rootFor)) { componentToDestroy.$__rootFor = null; componentToDestroy.$__destroyShallow(); } } } function destroyElRecursive(el) { var curChild = el.firstChild; while(curChild) { if (curChild.nodeType === 1) { destroyComponentForEl(curChild); destroyElRecursive(curChild); } curChild = curChild.nextSibling; } } function nextComponentId() { // Each component will get an ID that is unique across all loaded // marko runtimes. This allows multiple instances of marko to be // loaded in the same window and they should all place nice // together return 'b' + ((markoGlobal.uid)++); } function getElementById(doc, id) { return doc.getElementById(id); } function attachBubblingEvent(componentDef, handlerMethodName, extraArgs) { if (handlerMethodName) { var id = componentDef.id; return extraArgs ? [handlerMethodName, id, extraArgs] : [handlerMethodName, id]; } } function getMarkoPropsFromEl(el) { var virtualProps = el._vprops; if (virtualProps === undefined) { virtualProps = el.getAttribute('data-marko'); if (virtualProps) { virtualProps = JSON.parse(virtualProps); } el._vprops = virtualProps = virtualProps || EMPTY_OBJECT; } return virtualProps; } exports.$__runtimeId = runtimeId; exports.$__componentLookup = componentLookup; exports.$__getComponentForEl = getComponentForEl; exports.$__emitLifecycleEvent = emitLifecycleEvent; exports.$__destroyComponentForEl = destroyComponentForEl; exports.$__destroyElRecursive = destroyElRecursive; exports.$__nextComponentId = nextComponentId; exports.$__getElementById = getElementById; exports.$__attachBubblingEvent = attachBubblingEvent; exports.$__getMarkoPropsFromEl = getMarkoPropsFromEl; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 1 1 1 1 1 1 1 1 | var KEY = Symbol(); var isArray = Array.isArray; function UniqueId(out) { this.prefix = out.global.componentIdPrefix || 's'; // "s" is for server (we use "b" for the browser) this.nextId = 0; } function nextComponentId(out) { var global = out.global; var idProvider = global[KEY] || (global[KEY] = new UniqueId(out)); return idProvider.prefix + (idProvider.nextId++); } function attachBubblingEvent(componentDef, handlerMethodName, extraArgs) { if (handlerMethodName) { if (extraArgs) { var bubblingDomEvents = componentDef.$__bubblingDomEvents || ( componentDef.$__bubblingDomEvents = [] ); var eventIndex = bubblingDomEvents.length; if (extraArgs.length === 1) { var firstArg = extraArgs[0]; if (isArray(firstArg)) { bubblingDomEvents.push(extraArgs); } else { bubblingDomEvents.push(firstArg); } } else { bubblingDomEvents.push(extraArgs); } return handlerMethodName + ' ' + componentDef.id + ' ' + eventIndex; } else { return handlerMethodName + ' ' + componentDef.id; } } } exports.$__nextComponentId = nextComponentId; exports.$__server = true; exports.$__attachBubblingEvent = attachBubblingEvent; |
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| State-legacy.js | 10% | (5 / 50) | 0% | (0 / 18) | 0% | (0 / 8) | 10% | (5 / 50) | |
| defineComponent-legacy.js | 41.67% | (5 / 12) | 0% | (0 / 6) | 0% | (0 / 1) | 41.67% | (5 / 12) | |
| defineRenderer-legacy.js | 17.65% | (3 / 17) | 0% | (0 / 10) | 0% | (0 / 2) | 17.65% | (3 / 17) | |
| defineWidget-legacy-browser.js | 11.24% | (10 / 89) | 0% | (0 / 50) | 0% | (0 / 10) | 12.05% | (10 / 83) | |
| defineWidget-legacy.js | 16.67% | (1 / 6) | 0% | (0 / 4) | 0% | (0 / 1) | 16.67% | (1 / 6) | |
| renderer-legacy.js | 9.73% | (11 / 113) | 0% | (0 / 83) | 0% | (0 / 4) | 9.73% | (11 / 113) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | 1 1 1 1 1 | var extend = require('raptor-util/extend');
function ensure(state, propertyName) {
var proto = state.constructor.prototype;
if (!(propertyName in proto)) {
Object.defineProperty(proto, propertyName, {
get: function() {
return this.$__raw[propertyName];
},
set: function(value) {
if (value === undefined) {
// Don't store state properties with an undefined or null value
delete this.$__raw[name];
} else {
// Otherwise, store the new value in the component state
this.$__raw[name] = value;
}
}
});
}
}
function State(component) {
this.$__component = component;
this.$__raw = {};
this.$__dirty = false;
this.$__old = null;
this.$__changes = null;
this.$__forced = null; // An object that we use to keep tracking of state properties that were forced to be dirty
}
State.prototype = {
$__reset: function() {
var self = this;
self.$__dirty = false;
self.$__old = null;
self.$__changes = null;
self.$__forced = null;
},
$__replace: function(newState) {
var state = this;
var key;
var rawState = this.$__raw;
for (key in rawState) {
if (!(key in newState)) {
state.$__set(key, undefined, false /* ensure:false */, false /* forceDirty:false */);
}
}
for (key in newState) {
state.$__set(key, newState[key], true /* ensure:true */, false /* forceDirty:false */);
}
},
$__set: function(name, value, shouldEnsure, forceDirty) {
var rawState = this.$__raw;
if (shouldEnsure) {
ensure(this, name);
}
if (forceDirty) {
var forcedDirtyState = this.$__forced || (this.$__forced = {});
forcedDirtyState[name] = true;
} else if (rawState[name] === value) {
return;
}
if (!this.$__dirty) {
// This is the first time we are modifying the component state
// so introduce some properties to do some tracking of
// changes to the state
this.$__dirty = true; // Mark the component state as dirty (i.e. modified)
this.$__old = rawState;
this.$__raw = rawState = extend({}, rawState);
this.$__changes = {};
this.$__component.$__queueUpdate();
}
this.$__changes[name] = value;
if (value === undefined) {
// Don't store state properties with an undefined or null value
delete rawState[name];
} else {
// Otherwise, store the new value in the component state
rawState[name] = value;
}
},
toJSON: function() {
return this.$__raw;
}
};
module.exports = State;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 1 1 1 1 1 | /**
* Define a new UI component that includes component and renderer.
*
* @param {Object} def The definition of the UI component (component methods, component constructor, rendering methods, etc.)
* @return {Component} The resulting Component with renderer
*/
var defineRenderer;
var defineWidget;
module.exports = function defineComponent(def) {
if (def.$__isComponent) {
return def;
}
var renderer;
if (def.template || def.renderer) {
renderer = defineRenderer(def);
} else {
throw new Error('Expected "template" or "renderer"');
}
return defineWidget(def, renderer);
};
defineRenderer = require('./defineRenderer-legacy');
defineWidget = require('./defineWidget-legacy');
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 1 1 1 | var marko = require('../../');
var makeRenderable = require('../../runtime/renderable');
module.exports = function defineRenderer(renderingLogic) {
var renderer = renderingLogic.renderer;
if (renderer && renderer.$__isRenderer) {
return renderer;
}
var template = renderingLogic.template;
if (typeof template === 'string') {
template = marko.load(template);
}
if (!renderer) {
// Create a renderer function that takes care of translating
// the input properties to a view state. Also, this renderer
// takes care of re-using existing components.
renderer = function renderer(input, out) {
// Render the template associated with the component using the final template
// data that we constructed
template._(input, out, renderingLogic);
};
}
renderer.$__isRenderer = true;
renderer.createOut = template ? template.createOut : renderingLogic.createOut;
renderer.template = template;
makeRenderable(renderer, renderer);
return renderer;
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | 2 2 2 2 1 1 2 2 2 2 | 'use strict'; /* jshint newcap:false */ var BaseState; var BaseComponent; var inherit; module.exports = function defineWidget(def, renderer) { def = def.Widget || def; if (def.$__isComponent) { return def; } var ComponentClass = function() {}; var proto; if (typeof def === 'function') { proto = def.prototype; proto.init = def; } else if (typeof def === 'object') { proto = def; } else { throw TypeError(); } ComponentClass.prototype = proto; // We don't use the constructor provided by the user // since we don't invoke their constructor until // we have had a chance to do our own initialization. // Instead, we store their constructor in the "initComponent" // property and that method gets called later inside // init-components-browser.js function Component(id, doc) { BaseComponent.call(this, id, doc); } if (!proto.$__isComponent) { // Inherit from Component if they didn't already inherit(ComponentClass, BaseComponent); } // The same prototype will be used by our constructor after // we he have set up the prototype chain using the inherit function proto = Component.prototype = ComponentClass.prototype; proto.constructor = def.constructor = Component; // get legacy methods var init = proto.init; var onRender = proto.onRender; var onBeforeUpdate = proto.onBeforeUpdate; var onUpdate = proto.onUpdate; var onBeforeDestroy = proto.onBeforeDestroy; var onDestroy = proto.onDestroy; // delete legacy methods delete proto.init; delete proto.onRender; delete proto.onBeforeUpdate; delete proto.onUpdate; delete proto.onBeforeDestroy; delete proto.onDestroy; proto.getWidget = proto.getComponent; proto.getWidgets = proto.getComponents; // convert legacy to modern if (init || onRender) { proto.onMount = function() { var self = this; var config = this.$c; if (init) init.call(this, config); if (onRender) { onRender.call(this, { firstRender:true }); this.on('$__legacyRender', function() { self.$__didUpdate = true; }); } }; } if (onBeforeUpdate || onUpdate) { proto.onUpdate = function() { if (onBeforeUpdate) onBeforeUpdate.call(this); if (onUpdate) onUpdate.call(this); if (onRender && this.$__didUpdate) { this.$__didUpdate = false; onRender.call(this, {}); } }; } if (onBeforeDestroy || onDestroy) { proto.onDestroy = function() { if (onBeforeDestroy) onBeforeDestroy.call(this); if (onDestroy) onDestroy.call(this); }; } // Set a flag on the constructor function to make it clear this is // a component so that we can short-circuit this work later Component.$__isComponent = true; function State() { BaseState.apply(this, arguments); } inherit(State, BaseState); proto.$__State = State; if (!renderer) { renderer = ComponentClass.renderer || ComponentClass.prototype.renderer; if (renderer) { // Legacy support var createOut = renderer.createOut; if (typeof renderer !== 'function') { var rendererObject = renderer; renderer = function(input, out) { var rendererFunc = rendererObject.renderer || rendererObject.render; rendererFunc(input, out); }; renderer.createOut = createOut; } renderer.render = function(input) { var out = createOut(); renderer(input, out); return out.end(); }; } } if (renderer) { // Add the rendering related methods as statics on the // new component constructor function Component.renderer = proto.$__renderer = renderer; Component.render = renderer.render; Component.renderSync = renderer.renderSync; } return Component; }; BaseState = require('./State-legacy'); BaseComponent = require('../Component'); inherit = require('raptor-util/inherit'); require('../../jquery').patchComponent(); |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 1 | module.exports = function defineWidget(def, renderer) { if (def.$__isComponent) { return def; } if (renderer) { return { $__isComponent: true, renderer: renderer, render: renderer.render, renderSync: renderer.renderSync, template: renderer.template }; } else { return {$__isComponent: true}; } }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | 1 1 1 1 1 1 1 1 1 1 1 | var getComponentsContext = require('../ComponentsContext').$__getComponentsContext;
var componentsUtil = require('../util');
var componentLookup = componentsUtil.$__componentLookup;
var registry = require('../registry');
var modernRenderer = require('../renderer');
var resolveComponentKey = modernRenderer.$__resolveComponentKey;
var preserveComponentEls = modernRenderer.$__preserveComponentEls;
var handleBeginAsync = modernRenderer.$__handleBeginAsync;
var WIDGETS_BEGIN_ASYNC_ADDED_KEY = '$wa';
function createRendererFunc(templateRenderFunc, componentProps) {
var typeName = componentProps.type;
var roots = componentProps.roots;
var assignedId = componentProps.id;
return function renderer(input, out, renderingLogic) {
var outGlobal = out.global;
if (!outGlobal[WIDGETS_BEGIN_ASYNC_ADDED_KEY]) {
outGlobal[WIDGETS_BEGIN_ASYNC_ADDED_KEY] = true;
out.on('beginAsync', handleBeginAsync);
}
var getInitialProps;
var getTemplateData;
var getInitialState;
var getWidgetConfig;
var getInitialBody;
if (renderingLogic) {
getInitialProps = renderingLogic.getInitialProps;
getTemplateData = renderingLogic.getTemplateData;
getInitialState = renderingLogic.getInitialState;
getWidgetConfig = renderingLogic.getWidgetConfig;
getInitialBody = renderingLogic.getInitialBody;
}
var widgetConfig;
var componentBody;
var componentState;
var component = outGlobal.$w;
var fakeComponent;
var isRerender = component !== undefined;
var id = assignedId;
var isExisting;
var customEvents;
var scope;
if (component) {
id = component.id;
isExisting = true;
outGlobal.$w = null;
} else {
var componentArgs = out.$c;
if (componentArgs) {
out.$c = null;
scope = componentArgs[0];
if (scope) {
scope = scope.id;
}
var ref = componentArgs[1];
if (ref != null) {
ref = ref.toString();
}
id = id || resolveComponentKey(out, ref, scope);
customEvents = componentArgs[2];
delete input.$w;
}
}
var componentsContext = getComponentsContext(out);
id = id || componentsContext.$__nextComponentId();
if (registry.$__isServer && typeName) {
component = { id:id, typeName:typeName };
} else {
if (!component) {
if (isRerender) {
// Look in in the DOM to see if a component with the same ID and type already exists.
component = componentLookup[id];
if (component && component.$__type !== typeName) {
component = undefined;
}
}
if (component) {
isExisting = true;
} else {
isExisting = false;
// We need to create a new instance of the component
if (typeName) {
component = registry.$__createComponent(typeName, id);
}
}
}
}
if (input) {
if (getWidgetConfig) {
// If getWidgetConfig() was implemented then use that to
// get the component config. The component config will be passed
// to the component constructor. If rendered on the server the
// component config will be serialized to a JSON-like data
// structure and stored in a "data-w-config" attribute.
widgetConfig = getWidgetConfig(input, out);
} else {
widgetConfig = input.widgetConfig;
}
if (widgetConfig) {
component.$c = widgetConfig;
}
if (getInitialBody) {
// If we have component a component body then pass it to the template
// so that it is available to the component tag and can be inserted
// at the w-body marker
componentBody = getInitialBody(input, out);
}
// If we do not have state then we need to go through the process
// of converting the input to a component state, or simply normalizing
// the input using getInitialProps
if (getInitialProps) {
// This optional method is used to normalize input state
input = getInitialProps(input, out) || {};
}
if (getInitialState) {
// This optional method is used to derive the component state
// from the input properties
component.state = componentState = getInitialState(input, out);
}
if (!componentBody) {
// Default to using the nested content as the component body
componentBody = input.renderBody;
}
}
if (component && isExisting) {
if (!component.$__isDirty || !component.shouldUpdate(input, component.$__state)) {
if (customEvents) {
component.$__setCustomEvents(customEvents, scope);
}
preserveComponentEls(component, out, componentsContext);
return;
}
}
if (!component) {
fakeComponent = {};
} else {
componentState = component.$__rawState || componentState;
}
var templateInput = getTemplateData ?
getTemplateData(componentState, input, out) :
componentState || input || {};
var componentDef = componentsContext.$__beginComponent(component || fakeComponent);
componentDef.$__roots = roots;
componentDef.$__component = fakeComponent ? null : component;
componentDef.$__isExisting = isExisting;
componentDef.b = componentBody;
componentDef.c = function(widgetConfig) {
component.$c = widgetConfig;
};
componentDef.t = function(typeName) {
if (typeName) {
this.$__component = component = registry.$__createComponent(typeName, fakeComponent.id);
}
};
if (component && isExisting) {
component.$__emitLifecycleEvent('$__legacyRender');
}
// Render the template associated with the component using the final template
// data that we constructed
templateRenderFunc(templateInput, out, componentDef, componentDef);
if (customEvents && componentDef.$__component) {
if (registry.$__isServer) {
componentDef.$__customEvents = customEvents;
componentDef.$__scope = scope;
} else {
componentDef.$__component.$__setCustomEvents(customEvents, scope);
}
}
componentDef.$__end();
};
}
module.exports = createRendererFunc;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| body-transformer.js | 20% | (1 / 5) | 100% | (0 / 0) | 0% | (0 / 1) | 20% | (1 / 5) | |
| component-tag.js | 18.18% | (2 / 11) | 0% | (0 / 2) | 0% | (0 / 1) | 18.18% | (2 / 11) | |
| components-transformer.js | 6.12% | (3 / 49) | 0% | (0 / 46) | 0% | (0 / 2) | 6.12% | (3 / 49) | |
| getRequirePath-browser.js | 50% | (1 / 2) | 100% | (0 / 0) | 0% | (0 / 1) | 50% | (1 / 2) | |
| getRequirePath.js | 22.22% | (2 / 9) | 0% | (0 / 6) | 0% | (0 / 1) | 22.22% | (2 / 9) | |
| include-tag-browser.js | 45.45% | (5 / 11) | 0% | (0 / 4) | 0% | (0 / 1) | 45.45% | (5 / 11) | |
| include-tag.js | 66.67% | (2 / 3) | 100% | (0 / 0) | 0% | (0 / 1) | 66.67% | (2 / 3) | |
| init-components-tag-browser.js | 100% | (1 / 1) | 100% | (0 / 0) | 0% | (0 / 1) | 100% | (1 / 1) | |
| init-components-tag.js | 26.09% | (6 / 23) | 0% | (0 / 6) | 0% | (0 / 4) | 26.09% | (6 / 23) | |
| preserve-tag.js | 20% | (4 / 20) | 0% | (0 / 10) | 0% | (0 / 1) | 20% | (4 / 20) | |
| widget-types-tag.js | 17.39% | (4 / 23) | 0% | (0 / 4) | 0% | (0 / 1) | 17.39% | (4 / 23) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | 1 | 'use strict'; module.exports = function transform(el, context) { let initComponentsNode = context.createNodeForEl('init-components'); el.appendChild(initComponentsNode); // Make <await-reorderer> optional. Automatically insert it before the // body tag. let awaitReorderer = context.createNodeForEl('await-reorderer'); el.appendChild(awaitReorderer); }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 1 1 | 'use strict'; var BIND_WIDGET_KEY = Symbol(); module.exports = function codeGenerator(el, codegen) { var builder = codegen.builder; var context = codegen.context; var bodyFunc = builder.renderBodyFunction(el.body, [ builder.identifierOut(), builder.identifier('__component'), builder.identifier('state') ]); var componentProps = el.getAttributeValue('props'); var bindComponentVar = context.addStaticVar('marko_bindComponent', builder.require( builder.literal('marko/components/taglib/helpers/bindComponent'))); if (context.data[BIND_WIDGET_KEY] == null) { context.data[BIND_WIDGET_KEY] = 0; } var varName = context.addStaticVar( 'marko_bindComponent' + (context.data[BIND_WIDGET_KEY]++), builder.functionCall(bindComponentVar, [ componentProps ])); return builder.functionCall(varName, [bodyFunc, builder.identifierOut()]); }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | 1 1 1 | 'use strict';
var getTransformHelper = require('./util/getTransformHelper');
function tagDefinitionHasOverridingKeyAttribute(el, context) {
if (!el.hasAttribute('key')) {
return false;
}
var tagDef = el.tagDef;
if (tagDef && tagDef.hasAttribute('key')) {
return true;
}
return false;
}
module.exports = function transform(el, context) {
var transformHelper = getTransformHelper(el, context);
if (el.type === 'TemplateRoot') {
transformHelper.handleRootNodes();
return;
}
if (el.hasAttribute('w-body')) {
context.deprecate('The "w-body" attribute is deprecated. Please use "<include(...)" instead. See: https://github.com/marko-js/marko/issues/492');
let builder = context.builder;
let bodyValue = el.getAttributeValue('w-body');
el.removeAttribute('w-body');
let includeNode = context.createNodeForEl('include');
if (!bodyValue) {
bodyValue = builder.memberExpression(
builder.identifier('__component'),
builder.identifier('b'));
includeNode.data.bodySlot = true;
}
includeNode.addProp('_target', bodyValue);
el.appendChild(includeNode);
}
if (el.tagName === 'widget-types') {
context.setFlag('hasWidgetTypes');
} else if (el.tagName === 'include') {
transformHelper.handleComponentEvents();
transformHelper.handleIncludeNode(el);
transformHelper.getComponentArgs().compile(transformHelper);
return;
}
if (el.hasAttribute('w-el-id')) {
transformHelper.addError('"w-el-id" attribute is no longer allowed. Use "w-id" instead.');
return;
}
if (el.isFlagSet('hasComponentBind') || el.hasAttribute('w-bind')) {
el.setFlag('hasComponentBind');
transformHelper.handleComponentBind();
}
if (/* New preserve attributes */
el.hasAttribute('no-update') ||
el.hasAttribute('no-update-body') ||
el.hasAttribute('no-update-if') ||
el.hasAttribute('no-update-body-if') ||
/* Old preserve attributes */
el.hasAttribute('w-preserve') ||
el.hasAttribute('w-preserve-body') ||
el.hasAttribute('w-preserve-if') ||
el.hasAttribute('w-preserve-body-if')) {
transformHelper.handleComponentPreserve();
}
if (el.hasAttribute('key') || el.hasAttribute('ref') || el.hasAttribute('w-id')) {
if (!tagDefinitionHasOverridingKeyAttribute(el, context)) {
transformHelper.assignComponentId();
}
}
if (el.hasAttribute('for-key') || el.hasAttribute('for-ref') || el.hasAttribute('w-for')) {
transformHelper.handleComponentFor();
}
if (el.hasAttribute('w-body')) {
transformHelper.handleComponentBody();
}
// Handle w-preserve-attrs and :no-update attributes
transformHelper.handleComponentPreserveAttrs();
// Handle w-on* properties
transformHelper.handleComponentEvents();
// If we need to pass any information to a nested component then
// we start that information in the "out" so that it can be picked
// up later by the nested component. We call this "component args" and
// we generate compiled code that stores the component args in the out
// for the next component and then we also insert cleanup code to remove
// the data out of the out
transformHelper.getComponentArgs().compile(transformHelper);
};
|
| 1 2 3 4 | 1 | module.exports = function getRequirePath(target, template) { return template.getRequirePath(target); }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 1 1 | var resolveFrom = require('resolve-from');
module.exports = function getRequirePath(target, context) {
if (target === 'marko' || target.startsWith('marko/')) {
return target;
}
var resolvedTarget = resolveFrom(context.dirname, target);
if (!resolvedTarget) {
throw new Error('Unable to resolve "' + target + '" from "' + context.dirname + '"');
}
var requirePath = context.getRequirePath(resolvedTarget);
return requirePath;
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 1 1 1 1 1 | var normalInclude = require('../../taglibs/core/include-tag').$__doInclude;
var componentsUtil = require('../util');
var getElementById = componentsUtil.$__getElementById;
var getComponentsContext = require('../ComponentsContext').$__getComponentsContext;
module.exports = function include(input, out) {
if (!normalInclude(input, out)) {
var elId = input._elId;
// There's no body content so let's see if we should reuse
// the existing body content in the DOM
var existingEl = getElementById(out.$__document, elId);
if (existingEl) {
var componentsContext = getComponentsContext(out);
componentsContext.$__globalContext.$__preserveDOMNode(elId, true /* body only */);
}
}
};
|
| 1 2 3 4 5 6 7 | 1 1 | var normalInclude = require('../../taglibs/core/include-tag');
module.exports = function include(input, out) {
normalInclude(input, out);
};
|
| 1 2 3 4 | 1 | // This tag is a noop in the browser
module.exports = function noop() {};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 1 1 1 1 1 1 | const INIT_COMPONENTS_KEY = Symbol();
var writeInitComponentsCode = require('../').writeInitComponentsCode;
var ComponentsContext = require('../ComponentsContext');
function handleAwaitBeforeRender(eventArgs) {
if (eventArgs.clientReorder) {
var asyncFragmentOut = eventArgs.out;
asyncFragmentOut.data.components = new ComponentsContext(asyncFragmentOut, undefined, false);
}
}
function handleAwaitFinish(eventArgs) {
var asyncFragmentOut = eventArgs.out;
writeInitComponentsCode(asyncFragmentOut, false);
}
module.exports = function render(input, out) {
var global = out.global;
if (global[INIT_COMPONENTS_KEY] === undefined) {
global[INIT_COMPONENTS_KEY] = true;
out.on('await:beforeRender', handleAwaitBeforeRender);
out.on('await:finish', handleAwaitFinish);
if (out.isSync() === true) {
// Generate initialization code for any of the UI components that were
// rendered synchronously
writeInitComponentsCode(out, true);
} else {
// Generate initialization code for any of the UI components that were
// rendered asynchronously, but were outside an `<await>` tag
// (each `<await>` tag will have its own component initialization block)
var asyncOut = out.beginAsync({ last: true, timeout: -1 });
out.onLast(function(next) {
writeInitComponentsCode(asyncOut, true);
asyncOut.end();
next();
});
}
}
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 1 1 1 1 | var componentsUtil = require('../util');
var getElementById = componentsUtil.$__getElementById;
var getComponentsContext = require('../ComponentsContext').$__getComponentsContext;
module.exports = function render(input, out) {
var global = out.global;
if (global.$w !== undefined) {
var id = input.id;
// See if the DOM node with the given ID already exists.
// If so, then reuse the existing DOM node instead of re-rendering
// the children. We have to put a placeholder node that will get
// replaced out if we find that the DOM node has already been rendered
var condition = input['if'];
if (condition !== false) {
var existingEl = getElementById(out.$__document, id);
if (existingEl) {
var componentsContext = getComponentsContext(out);
var bodyOnly = input.bodyOnly === true;
// Don't actually render anything since the element is already in the DOM,
// but keep track that the node is being preserved so that we can ignore
// it while transforming the old DOM
if (!bodyOnly) {
var tagName = existingEl.tagName;
// If we are preserving the entire DOM node (not just the body)
// then that means that we have need to render a placeholder to
// mark the target location. We can then replace the placeholder
// node with the existing DOM node
out.element(tagName, { id: id });
}
componentsContext.$__globalContext.$__preserveDOMNode(id, bodyOnly);
return;
}
}
}
if (input.renderBody) {
input.renderBody(out);
}
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 1 1 1 1 | 'use strict';
const getTransformHelper = require('./util/getTransformHelper');
const generateRegisterComponentCode = require('./util/generateRegisterComponentCode');
const resolveFrom = require('resolve-from');
module.exports = function codeGenerator(el, codegen) {
var context = codegen.context;
var transformHelper = getTransformHelper(el, context);
transformHelper.isLegacyComponent = true;
var builder = codegen.builder;
var attrs = el.getAttributes();
var typesObject = {};
attrs.forEach((attr) => {
if (!attr.isLiteralString()) {
codegen.addError('Component type should be a string');
return;
}
let requirePath = attr.literalValue;
let filename = resolveFrom(transformHelper.dirname, requirePath);
if (!filename) {
transformHelper.addError('Target file not found: ' + requirePath + ' (from: ' + transformHelper.dirname + ')');
return;
}
let componentModule = {
legacy: true,
filename: filename,
requirePath: requirePath
};
typesObject[attr.name] = generateRegisterComponentCode(componentModule, transformHelper, false);
});
codegen.addStaticVar('marko_componentTypes', builder.literal(typesObject));
return null;
};
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| ComponentArgs.js | 2.44% | (1 / 41) | 0% | (0 / 14) | 0% | (0 / 6) | 2.44% | (1 / 41) | |
| assignComponentId.js | 1.54% | (1 / 65) | 0% | (0 / 32) | 0% | (0 / 2) | 1.54% | (1 / 65) | |
| getComponentFiles.js | 15.38% | (4 / 26) | 0% | (0 / 10) | 0% | (0 / 1) | 15.38% | (4 / 26) | |
| handleComponentBind.js | 3.97% | (5 / 126) | 0% | (0 / 76) | 0% | (0 / 5) | 3.97% | (5 / 126) | |
| handleComponentEvents.js | 10.75% | (10 / 93) | 0% | (0 / 42) | 14.29% | (1 / 7) | 10.75% | (10 / 93) | |
| handleComponentFor.js | 4.35% | (1 / 23) | 0% | (0 / 14) | 0% | (0 / 1) | 4.35% | (1 / 23) | |
| handleComponentPreserve.js | 11.11% | (8 / 72) | 0% | (0 / 26) | 0% | (0 / 7) | 11.11% | (8 / 72) | |
| handleComponentPreserveAttrs.js | 14.81% | (4 / 27) | 0% | (0 / 10) | 0% | (0 / 2) | 14.81% | (4 / 27) | |
| handleIncludeNode.js | 8% | (2 / 25) | 0% | (0 / 14) | 0% | (0 / 2) | 8% | (2 / 25) | |
| handleRootNodes.js | 6.72% | (9 / 134) | 0% | (0 / 76) | 0% | (0 / 6) | 6.72% | (9 / 134) | |
| index.js | 22.95% | (14 / 61) | 0% | (0 / 15) | 0% | (0 / 23) | 22.95% | (14 / 61) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | 1 | 'use strict';
class ComponentArgs {
constructor() {
this.id = null;
this.customEvents = null;
this.empty = true;
}
setId(id) {
this.empty = false;
this.id = id;
}
getId() {
return this.id;
}
addCustomEvent(eventType, targetMethod, extraArgs) {
this.empty = false;
if (!this.customEvents) {
this.customEvents = [];
}
this.customEvents.push([eventType, targetMethod, extraArgs]);
}
compile(transformHelper) {
if (this.empty) {
return;
}
var el = transformHelper.el;
var builder = transformHelper.builder;
var id = this.id;
var customEvents = this.customEvents;
// Make sure the nested component has access to the ID of the containing
// component if it is needed
var shouldProvideScope = id || customEvents;
var args = [];
if (shouldProvideScope) {
args.push(builder.identifier('__component'));
} else {
args.push(builder.literalNull());
}
if (id != null) {
args.push(id);
} else {
args.push(builder.literalNull());
}
if (customEvents) {
args.push(builder.literal(customEvents));
}
if (el.type === 'CustomTag') {
var renderComponentHelper = transformHelper.context.helper('renderComponent');
el.generateRenderTagCode = function(codegen, tagVar, tagArgs) {
tagArgs = [tagVar].concat(tagArgs);
tagArgs.push(builder.literal(args));
return codegen.builder.functionCall(
renderComponentHelper,
tagArgs);
};
} else {
el.onBeforeGenerateCode((event) => {
let lhs = builder.memberExpression(builder.identifierOut(), builder.identifier('$c'));
let rhs = builder.literal(args);
event.insertCode(builder.assignment(lhs, rhs));
});
el.onAfterGenerateCode((event) => {
let lhs = builder.memberExpression(builder.identifierOut(), builder.identifier('$c'));
let rhs = builder.literalNull();
event.insertCode(builder.assignment(lhs, rhs));
});
}
}
}
module.exports = ComponentArgs;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | 1 | 'use strict'; module.exports = function assignComponentId(isRepeated) { // First check if we have already assigned an ID to thie element var componentIdInfo = this.componentIdInfo; if (componentIdInfo) { return this.componentIdInfo; } var el = this.el; var context = this.context; var builder = this.builder; let componentRef; var nestedIdExpression; var idExpression; if (!this.hasBoundComponentForTemplate()) { // We are assigning a component ID to a nested component in a template that does not have a component. // That means we do not have access to the parent component variable as part of a closure. We // need to look it up out of the `out.data` map if (!context.isFlagSet('hasComponentVar')) { context.setFlag('hasComponentVar'); var getCurrentComponentVar = context.importModule('marko_getCurrentComponent', this.getMarkoComponentsRequirePath('marko/components/taglib/helpers/getCurrentComponent')); context.addVar('__component', builder.functionCall(getCurrentComponentVar, [builder.identifierOut()])); } } // In order to attach a DOM event listener directly we need to make sure // the target HTML element has an ID that we can use to get a reference // to the element during initialization. We generate this unique ID // at compile-time to allow consistent IDs during rendering. // We need to handle the following scenarios: // // 1) The HTML element already has an "id" attribute // 2) The HTML element has a "ref" or "w-id" attribute (we already converted this // to an "id" attribute above) // 3) The HTML does not have an "id" or "ref" attribute. We must add // an "id" attribute with a unique ID. var isCustomTag = el.type !== 'HtmlElement'; if (el.hasAttribute('key')) { componentRef = el.getAttributeValue('key'); el.removeAttribute('key'); } else if (el.hasAttribute('ref')) { context.deprecate('The "ref" attribute is deprecated. Please use "key" instead.'); componentRef = el.getAttributeValue('ref'); el.removeAttribute('ref'); } if (el.hasAttribute('w-id')) { context.deprecate('The "w-id" attribute is deprecated. Please use "key" instead.'); if (componentRef) { this.addError('The "w-id" attribute cannot be used in conjuction with the "ref" or "key" attributes.'); return; } componentRef = el.getAttributeValue('w-id'); el.removeAttribute('w-id'); } if (componentRef) { idExpression = this.buildComponentElIdFunctionCall(componentRef); nestedIdExpression = componentRef; if (isCustomTag) { // The element is a custom tag this.getComponentArgs().setId(nestedIdExpression); } else { if (el.hasAttribute('id')) { this.addError('The "ref", "key", and "w-id" attributes cannot be used in conjuction with the "id" attribute.'); return; } el.setAttributeValue('id', idExpression); } } else if (el.hasAttribute('id')) { idExpression = el.getAttributeValue('id'); if (el.isFlagSet('hasComponentBind')) { // We have to attach a listener to the root element of the component // We will use an empty string as an indicator that it is the root component // element. nestedIdExpression = builder.literal(''); } else { // Convert the raw String to a JavaScript expression. we need to prefix // with '#' to make it clear this is a fully resolved element ID nestedIdExpression = builder.concat( builder.literal('#'), idExpression); } } else { // Case 3 - We need to add a unique "id" attribute let uniqueElId = this.nextUniqueId(); nestedIdExpression = isRepeated ? builder.literal(uniqueElId + '[]') : builder.literal(uniqueElId); idExpression = this.buildComponentElIdFunctionCall(nestedIdExpression); if (isCustomTag) { this.getComponentArgs().setId(nestedIdExpression); } else { el.setAttributeValue('id', idExpression); } } var transformHelper = this; this.componentIdInfo = { idExpression: idExpression, nestedIdExpression: nestedIdExpression, idVarNode: null, createIdVarNode: function() { if (this.idVarNode) { return this.idVarNode; } let uniqueElId = transformHelper.nextUniqueId(); let idVarName = '__componentId' + uniqueElId; let idVar = builder.identifier(idVarName); this.idVarNode = builder.vars([ { id: idVarName, init: idExpression } ]); this.idExpression = idExpression = idVar; this.nestedIdExpression = nestedIdExpression = builder.concat( builder.literal('#'), idVar); if (isCustomTag) { transformHelper.getComponentArgs().setId(nestedIdExpression); } else { el.setAttributeValue('id', idExpression); } return this.idVarNode; } }; return this.componentIdInfo; }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | 1 1 1 1 | 'use strict';
var fs = require('fs');
var path = require('path');
function getComponentFiles(filename) {
var ext = path.extname(filename);
if (ext === '.js') {
return null;
}
var nameNoExt = path.basename(filename, ext);
var isEntry = 'index' === nameNoExt;
var fileMatch = '('+nameNoExt.replace(/\./g, '\\.') + '\\.' + (isEntry ? '|' : '') + ')';
var styleMatch = new RegExp('^'+fileMatch+'style\\.\\w+$');
var componentMatch = new RegExp('^'+fileMatch+'component\\.\\w+$');
var splitComponentMatch = new RegExp('^'+fileMatch+'component-browser\\.\\w+$');
var dirname = path.dirname(filename);
var foundFiles = {
styles: [],
file: null,
browserFile: null
};
var dirFiles = fs.readdirSync(dirname);
dirFiles.sort();
for (let i=dirFiles.length - 1; i>=0; i--) {
let file = dirFiles[i];
if (styleMatch.test(file)) {
foundFiles.styles.push(file);
} else if (splitComponentMatch.test(file)) {
foundFiles.browserFile = file;
} else if (componentMatch.test(file)) {
foundFiles.file = file;
}
}
return foundFiles;
}
module.exports = getComponentFiles;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | 1 1 1 1 1 | 'use strict';
const resolveFrom = require('resolve-from');
const generateRegisterComponentCode = require('../util/generateRegisterComponentCode');
function legacyGetDefaultComponentModule(dirname) {
var filename;
var legacy = true;
if ((filename = resolveFrom(dirname, './widget'))) {
return {
filename,
requirePath: './widget',
legacy
};
} else if ((filename = resolveFrom(dirname, './component'))) {
return {
filename,
requirePath: './component',
legacy
};
} else if ((filename = resolveFrom(dirname, './'))) {
return {
filename,
requirePath: './',
legacy
};
} else {
return null;
}
}
function checkIsInnerBind(el) {
var curNode = el;
while (true) {
if (curNode.data.hasBoundComponent) {
return true;
}
curNode = curNode.parentNode;
if (!curNode) {
break;
}
}
return false;
}
module.exports = function handleComponentBind() {
let el = this.el;
let context = this.context;
let builder = this.builder;
let componentModule;
let rendererModulePath;
let rendererModule = this.getRendererModule();
let isLegacyComponent = false;
if (el.hasAttribute('w-bind')) {
let bindAttr = el.getAttribute('w-bind');
context.deprecate('Legacy components using w-bind and defineRenderer/defineComponent or defineComponent are deprecated. See: https://github.com/marko-js/marko/issues/421');
this.isLegacyComponent = isLegacyComponent = true;
// Remove the w-bind attribute since we don't want it showing up in the output DOM
el.removeAttribute('w-bind');
// Read the value for the w-bind attribute. This will be an AST node for the parsed JavaScript
let bindAttrValue = bindAttr.value;
const hasWidgetTypes = context.isFlagSet('hasWidgetTypes');
if (hasWidgetTypes) {
context.deprecate('The <widget-types> tag is deprecated. Please remove it. See: https://github.com/marko-js/marko/issues/514');
}
if (bindAttrValue == null) {
componentModule = legacyGetDefaultComponentModule(this.dirname);
if (!componentModule) {
this.addError('No corresponding JavaScript module found in the same directory (either "component.js" or "index.js").');
return;
}
} else if (bindAttr.isLiteralValue()) {
if (typeof bindAttr.literalValue !== 'string') {
this.addError('The value for the "w-bind" attribute should be a string. Actual: ' + componentModule);
return;
}
let requirePath = bindAttr.literalValue;
let filename = resolveFrom(this.dirname, requirePath);
if (!filename) {
this.addError('Target file not found: ' + requirePath + ' (from: ' + this.dirname + ')');
return;
}
componentModule = {
legacy: true,
filename,
requirePath
};
} else {
// This is a dynamic expression. The <widget-types> should have been found.
if (!hasWidgetTypes) {
this.addError('The <widget-types> tag must be used to declare components when the value of the "w-bind" attribute is a dynamic expression.');
return;
}
el.insertSiblingBefore(
builder.functionCall(
builder.memberExpression(builder.identifier('__component'), builder.identifier('t')),
[
builder.memberExpression(
builder.identifier('marko_componentTypes'),
bindAttrValue,
true /* computed */)
]));
}
} else if (el.isFlagSet('hasComponentBind')) {
componentModule = this.getComponentModule();
rendererModulePath = this.getRendererModule();
if (context.isFlagSet('hasWidgetTypes')) {
context.addError('The <widget-types> tag is no longer supported. See: https://github.com/marko-js/marko/issues/514');
}
} else {
return;
}
this.setHasBoundComponentForTemplate();
let isInnerBind = checkIsInnerBind(el.parentNode);
el.data.hasBoundComponent = true;
// A component is bound to the el...
var componentProps = isInnerBind ? {} : this.getComponentProps();
let transformHelper = this;
var isSplit = false;
if ((rendererModule && rendererModule !== componentModule) ||
(!rendererModule && componentModule)) {
componentProps.split = isSplit = true;
}
if (componentModule) {
let componentTypeNode;
let dependencyModule = isLegacyComponent || isSplit ? componentModule : this.getTemplateModule();
if (dependencyModule.requirePath) {
context.addDependency({ type:'require', path: dependencyModule.requirePath });
}
if (isSplit) {
context.addDependency({ type:'require', path: 'marko/components' });
}
componentTypeNode = context.addStaticVar(
'marko_componentType',
generateRegisterComponentCode(componentModule, this, isSplit));
componentProps.type = componentTypeNode;
}
if (el.hasAttribute('w-config')) {
el.insertSiblingBefore(
builder.functionCall(
builder.memberExpression(builder.identifier('__component'), builder.identifier('c')),
[
el.getAttributeValue('w-config')
]));
el.removeAttribute('w-config');
}
let id = el.getAttributeValue('id');
if (id) {
componentProps.id = id;
}
let markoComponentVar;
if (rendererModule) {
if (rendererModule.inlineId) {
markoComponentVar = rendererModule.inlineId;
} else {
markoComponentVar = context.addStaticVar('marko_component', builder.require(builder.literal(rendererModule.requirePath)));
}
}
if (isInnerBind) {
el.setAttributeValue('id',
builder.memberExpression(
builder.identifier('__component'),
builder.identifier('id')));
// TODO Deprecation warning for inner binds
let componentNode = context.createNodeForEl('_component', {
props: builder.literal(componentProps)
});
el.wrapWith(componentNode);
return;
}
if (this.firstBind) {
this.context.on('beforeGenerateCode:TemplateRoot', function(eventArgs) {
eventArgs.node.addRenderFunctionParam(builder.identifier('__component'));
if (isLegacyComponent) {
eventArgs.node.addRenderFunctionParam(builder.identifier('widget'));
} else {
eventArgs.node.addRenderFunctionParam(builder.identifier('component'));
eventArgs.node.addRenderFunctionParam(builder.identifier('state'));
}
eventArgs.node.generateAssignRenderCode = function(eventArgs) {
let nodes = [];
let templateVar = eventArgs.templateVar;
let templateRendererMember = eventArgs.templateRendererMember;
let renderFunctionVar = eventArgs.renderFunctionVar;
let createRendererArgs = [
renderFunctionVar,
builder.literal(componentProps)
];
if (markoComponentVar) {
createRendererArgs.push(markoComponentVar);
}
nodes.push(builder.assignment(
templateRendererMember,
builder.functionCall(
builder.memberExpression(transformHelper.markoComponentsVar, builder.identifier('r')),
createRendererArgs)));
if (!isSplit && !isLegacyComponent) {
nodes.push(builder.assignment(
builder.memberExpression(templateVar, builder.identifier('Component')),
builder.functionCall(
builder.memberExpression(transformHelper.markoComponentsVar, builder.identifier('c')),
[
markoComponentVar,
templateRendererMember
])));
}
return nodes;
};
});
}
if (el.hasAttribute('key')) {
if (!componentProps.roots) {
componentProps.roots = [];
}
var key = el.getAttributeValue('key');
componentProps.roots.push(key);
} else if (el.hasAttribute('ref')) {
if (!componentProps.roots) {
componentProps.roots = [];
}
var ref = el.getAttributeValue('ref');
componentProps.roots.push(ref);
} else {
el.setAttributeValue('id',
builder.memberExpression(
builder.identifier('__component'),
builder.identifier('id')));
}
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | 1 1 1 18 1 1 1 1 1 1 | 'use strict';
var ATTACH_DETACH_KEY = Symbol('attach-detach');
var bubbleEventsLookup = {};
require('../../bubble').forEach(function(eventType) {
bubbleEventsLookup[eventType] = true;
});
function isBubbleEvent(eventType) {
return bubbleEventsLookup.hasOwnProperty(eventType);
}
function isUpperCase(c) {
return c == c.toUpperCase();
}
function addBubblingEventListener(transformHelper, eventType, targetMethod, extraArgs) {
var el = transformHelper.el;
if (transformHelper.hasBoundComponentForTemplate() === false) {
transformHelper.addError('Unable to handle event ' + eventType + '. HTML element is not nested within a component.');
return;
}
var builder = transformHelper.builder;
var addBubblingEventMethod = builder.memberExpression(
builder.identifier('__component'),
builder.identifier('d'));
var addBubblingEventArgs = [
targetMethod
];
if (extraArgs) {
addBubblingEventArgs.push(builder.arrayExpression(extraArgs));
}
var propValue = builder.functionCall(addBubblingEventMethod, addBubblingEventArgs);
var propName = 'on' + eventType.value;
el.setPropertyValue(propName, propValue, false);
if (eventType.value === 'attach' || eventType.value === 'detach') {
if (!transformHelper.context.data[ATTACH_DETACH_KEY]) {
transformHelper.context.data[ATTACH_DETACH_KEY] = true;
let requireFuncCall = builder.require(builder.literal('marko/components/attach-detach'));
transformHelper.context.addStaticCode(requireFuncCall);
}
}
}
function addDirectEventListener(transformHelper, eventType, targetMethod, extraArgs) {
var builder = transformHelper.builder;
var el = transformHelper.el;
var addDomEvent = builder.memberExpression(
builder.identifier('__component'),
builder.identifier('e'));
let componentIdInfo = transformHelper.assignComponentId(true /* repeated */);
let idVarNode = componentIdInfo.idVarNode ? null : componentIdInfo.createIdVarNode();
var helperArgs = [
eventType,
targetMethod,
componentIdInfo.idExpression
];
if (extraArgs) {
helperArgs.push(builder.arrayExpression(extraArgs));
}
var addDomEventFunctionCall = builder.functionCall(addDomEvent, helperArgs);
el.onBeforeGenerateCode((event) => {
event.insertCode([
idVarNode,
addDomEventFunctionCall
]);
});
}
function addCustomEventListener(transformHelper, eventType, targetMethod, extraArgs) {
var builder = transformHelper.builder;
// Make sure the component has an assigned scope ID so that we can bind the custom event listener
var componentArgs = transformHelper.getComponentArgs();
if (extraArgs) {
extraArgs = builder.arrayExpression(extraArgs);
}
componentArgs.addCustomEvent(eventType, targetMethod, extraArgs);
}
module.exports = function handleComponentEvents() {
var el = this.el;
var builder = this.builder;
var context = this.context;
var isCustomTag = el.type !== 'HtmlElement';
// We configured the Marko compiler to attach a flag to nodes that
// have one or more attributes that match the "w-on*" pattern.
// We still need to loop over the properties to find and handle
// the properties corresponding to those attributes.
var hasComponentEvents = this.el.isFlagSet('hasComponentEvents') === true;
if (hasComponentEvents) {
var attrs = el.getAttributes().concat([]);
attrs.forEach((attr) => {
var eventType;
var targetMethod;
var attrName = attr.name;
var argument = attr.argument;
var parsedArgs;
var extraArgs;
if (!attrName) {
return;
}
if (attrName.startsWith('on') && argument) {
eventType = attrName.substring(2); // Chop off "on"
try {
parsedArgs = builder.parseJavaScriptArgs(argument);
} catch (err) {
this.addError('Invalid Javascript Expression for "' + attrName + '": ' + err);
return;
}
targetMethod = builder.replacePlaceholderEscapeFuncs(parsedArgs[0], context);
if (parsedArgs.length > 1) {
extraArgs = parsedArgs.slice(1);
}
} else if (attrName.startsWith('w-on')) {
context.deprecate('"w-on*" attributes are deprecated. Please use "on*()" instead.');
eventType = attrName.substring(4); // Chop off "w-on"
targetMethod = attr.value;
}
if (!eventType || !targetMethod) {
return;
}
el.removeAttribute(attrName);
if (isCustomTag) {
this.assignComponentId(true /* repeated */);
// We are adding an event listener for a custom event (not a DOM event)
if (eventType.startsWith('-')) {
// Remove the leading dash.
// Example: w-on-before-show → before-show
eventType = eventType.substring(1);
} else if (isUpperCase(eventType.charAt(0))) {
// Convert first character to lower case:
// Example: w-onBeforeShow → beforeShow
eventType = eventType.charAt(0).toLowerCase() + eventType.substring(1);
}
eventType = builder.literal(eventType);
// Node is for a custom tag
addCustomEventListener(this, eventType, targetMethod, extraArgs);
} else {
// We are adding an event listener for a DOM event (not a custom event)
//
if (eventType.startsWith('-')) {
// Remove the leading dash.
// Example: w-on-before-show → before-show
eventType = eventType.substring(1);
}
// Normalize DOM event types to be all lower case
eventType = eventType.toLowerCase();
// Node is for an HTML element so treat the event as a DOM event
var willBubble = isBubbleEvent(eventType);
eventType = builder.literal(eventType);
if (willBubble) {
// The event is white listed for bubbling so we know that
// we have already attached a listener on document.body
// that can be used to handle the event. We will add
// a "data-w-on{eventType}" attribute to the output HTML
// for this element that will be used to map the event
// to a method on the containing component.
addBubblingEventListener(this, eventType, targetMethod, extraArgs);
} else {
// The event does not bubble so we must attach a DOM
// event listener directly to the target element.
addDirectEventListener(this, eventType, targetMethod, extraArgs);
}
}
});
}
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | 1 | module.exports = function handleComponentFor() { var el = this.el; var context = this.context; var componentFor; if (el.hasAttribute('for-ref')) { context.deprecate('The "for-ref" tag is deprecated. Please use "for-key" instead.'); componentFor = el.getAttributeValue('for-ref'); el.removeAttribute('for-ref'); } else if (el.hasAttribute('for-key')) { componentFor = el.getAttributeValue('for-key'); el.removeAttribute('for-key'); } if (el.hasAttribute('w-for')) { context.deprecate('The "w-for" tag is deprecated. Please use "for-ref" instead.'); if (componentFor) { this.addError('The "w-for" tag cannot be used with "for-ref" or "for-key".'); return; } else { componentFor = el.getAttributeValue('w-for'); } el.removeAttribute('w-for'); } if (componentFor == null) { return; } // Handle the "for-ref" attribute if (el.hasAttribute('for')) { this.addError('The "for-ref", "for-key", and "w-for" attribute cannot be used in conjuction with the "for" attribute. (' + (el.pos ? context.getPosInfo(el.pos) : context.filename) + ')'); } else { el.setAttributeValue( 'for', this.buildComponentElIdFunctionCall(componentFor)); } }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | 1 1 1 1 1 1 1 1 | 'use strict'; function addPreserve(transformHelper, bodyOnly, condition) { let el = transformHelper.el; let context = transformHelper.context; let builder = transformHelper.builder; let preserveAttrs = {}; if (bodyOnly) { preserveAttrs['body-only'] = builder.literal(bodyOnly); } if (condition) { preserveAttrs['if'] = condition; } let componentIdInfo = transformHelper.assignComponentId(true /* repeated */); let idVarNode = componentIdInfo.idVarNode ? null : componentIdInfo.createIdVarNode(); preserveAttrs.id = transformHelper.getIdExpression(); let preserveNode = context.createNodeForEl('w-preserve', preserveAttrs); let idVarNodeTarget; if (bodyOnly) { el.moveChildrenTo(preserveNode); el.appendChild(preserveNode); idVarNodeTarget = el; } else { el.wrapWith(preserveNode); idVarNodeTarget = preserveNode; } if (idVarNode) { idVarNodeTarget.onBeforeGenerateCode((event) => { event.insertCode(idVarNode); }); } return preserveNode; } function deprecatedWarning(preserveType, transformHelper, el) { let attribute = preserveType.attribute; let suffix = preserveType.suffix; let context = transformHelper.getCompileContext(); let newAttributeName = 'no-update'; if (suffix) { newAttributeName += suffix; } context.deprecate(`The '${attribute}' attribute is deprecated. Please use '${newAttributeName}' instead.`); } function preserveHandler(transformHelper, preserveType, el) { if (preserveType.deprecated) { deprecatedWarning(preserveType, transformHelper, el); } el.removeAttribute(preserveType.attribute); addPreserve(transformHelper, false); } function preserveIfHandler(transformHelper, preserveType, el) { if (preserveType.deprecated) { deprecatedWarning(preserveType, transformHelper, el); } let attribute = preserveType.attribute; let preserveIfAttr = el.getAttribute(attribute); let preserveIfCondition = preserveIfAttr.argument; if (!preserveIfCondition) { transformHelper.addError(`The '${attribute}' attribute should have an argument. For example: <div ${attribute}(someCondition)>`); return; } addPreserve(transformHelper, false, transformHelper.builder.expression(preserveIfCondition)); el.removeAttribute(attribute); } function preserveBodyHandler(transformHelper, preserveType, el) { if (preserveType.deprecated) { deprecatedWarning(preserveType, transformHelper, el); } el.removeAttribute(preserveType.attribute); addPreserve(transformHelper, true); } function preserveBodyIfHandler(transformHelper, preserveType, el) { if (preserveType.deprecated) { deprecatedWarning(preserveType, transformHelper, el); } let attribute = preserveType.attribute; let preserveBodyIfAttr = el.getAttribute(attribute); let preserveBodyIfCondition = preserveBodyIfAttr.argument; if (!preserveBodyIfCondition) { transformHelper.addError(`The '${attribute}' attribute should have an argument. For example: <div ${attribute}(someCondition)>`); return; } addPreserve(transformHelper, true, transformHelper.builder.expression(preserveBodyIfCondition)); } const preserveTypes = [ // The new preserve types { attribute: 'no-update', handler: preserveHandler }, { attribute: 'no-update-if', handler: preserveIfHandler }, { attribute: 'no-update-body', handler: preserveBodyHandler }, { attribute: 'no-update-body-if', handler: preserveBodyIfHandler }, // The deprecated preserve types { attribute: 'w-preserve', handler: preserveHandler, deprecated: true }, { attribute: 'w-preserve-if', suffix: '-if', handler: preserveIfHandler, deprecated: true }, { attribute: 'w-preserve-body', suffix: '-body', handler: preserveBodyHandler, deprecated: true }, { attribute: 'w-preserve-body-if', suffix: '-body-if', handler: preserveBodyIfHandler, deprecated: true } ]; module.exports = function handleComponentPreserve() { let el = this.el; for (let i = 0; i < preserveTypes.length; i++) { let preserveType = preserveTypes[i]; if (el.hasAttribute(preserveType.attribute)) { preserveType.handler(this, preserveType, el); el.removeAttribute(preserveType.attribute); return; } } }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | 1 1 1 1 | const NO_UPDATE_ATTR_SUFFIX = ':no-update';
var PRESERVE_ATTRS_HELPER_ADDED = Symbol('PRESERVE_ATTRS_HELPER_ADDED');
function handleComponentPreserveAttrs() {
var el = this.el;
var context = this.context;
var builder = context.builder;
var noUpdateAttrs = [];
el.forEachAttribute(function(attr) {
var attrName = attr.name;
if (attrName && attrName.endsWith(NO_UPDATE_ATTR_SUFFIX)) {
var attrIndex = attrName.indexOf(NO_UPDATE_ATTR_SUFFIX);
var attrValue = el.getAttributeValue(attrName);
// Set the attribute value for the real attribute name without the
// :no-update suffix, and remove the :no-update suffix attribute
var realAttr = attrName.substr(0, attrIndex);
el.setAttributeValue(realAttr, attrValue);
el.removeAttribute(attrName);
noUpdateAttrs.push(realAttr);
} else if (attrName === 'w-preserve-attrs') {
context.deprecate(`The 'w-preserve-attrs' attribute is deprecated. Please use the ':no-update' attribute instead.`);
var preserveAttrsExpression = el.getAttributeValue('w-preserve-attrs');
noUpdateAttrs.push.apply(noUpdateAttrs, preserveAttrsExpression.value.split(','));
el.removeAttribute('w-preserve-attrs');
}
});
if (noUpdateAttrs.length) {
el.setPropertyValue('noupdate', builder.literal(noUpdateAttrs));
if (!context.isFlagSet(PRESERVE_ATTRS_HELPER_ADDED)) {
context.setFlag(PRESERVE_ATTRS_HELPER_ADDED);
context.addStaticCode(
this.builder.require(
this.builder.literal('marko/runtime/vdom/preserve-attrs')));
}
}
}
module.exports = handleComponentPreserveAttrs;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | 1 1 | 'use strict';
var includeTagForComponents = require.resolve('../include-tag');
module.exports = function(includeNode) {
var context = this.context;
if (!this.hasBoundComponentForTemplate()) {
return;
}
var parentNode = includeNode.parentNode;
if (!parentNode.hasAttribute) {
return;
}
parentNode._normalizeChildTextNodes(context, true /* force trim */);
if (parentNode.childCount === 1) {
if (includeNode.hasAttribute('key') || includeNode.hasAttribute('ref')) {
this.assignComponentId();
}
let parentTransformHelper = this.getTransformHelper(parentNode);
if (includeNode.data.bodySlot) {
parentTransformHelper.assignComponentId(false /* not repeated */);
var componentProps = this.getComponentProps();
componentProps.body = parentTransformHelper.getNestedIdExpression();
} else {
let componentIdInfo = parentTransformHelper.assignComponentId(true /* repeated */);
if (!componentIdInfo.idVarNode) {
let idVarNode = componentIdInfo.createIdVarNode();
parentNode.onBeforeGenerateCode((event) => {
event.insertCode(idVarNode);
});
}
}
includeNode.setRendererPath(includeTagForComponents);
includeNode.onBeforeGenerateCode(function() {
includeNode.addProp('_elId', parentTransformHelper.getIdExpression());
});
}
// includeNode.generateCodeForDynamicInclude = (options, codegen) => {
// var target = options.target;
// var data = options.data;
//
// if (!data) {
// data = builder.literal(null);
// }
//
// let includeVar = context.importModule('marko_component_include', this.getMarkoComponentsRequirePath('marko/components/taglib/helpers/include'));
//
// let includeArgs = [
// target,
// builder.identifierOut(),
// data
// ];
//
// if (parentTransformHelper) {
// includeArgs = includeArgs.concat([
// parentTransformHelper.getIdExpression(),
//
// ]);
// }
//
// return builder.functionCall(includeVar, includeArgs);
// };
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | 1 1 1 1 1 1 1 1 1 | 'use strict';
var path = require('path');
var getComponentFiles = require('./getComponentFiles');
const esprima = require('esprima');
const escodegen = require('escodegen');
function handleStyleElement(styleEl, transformHelper) {
if (styleEl.bodyText) {
return;
}
var attrs = styleEl.attributes;
var styleCode;
var lang = 'css';
var hasStyleBlock = false;
for (var i=attrs.length-1; i>=0; i--) {
var attr = attrs[i];
var name = attr.name;
if (name.startsWith('{')) {
hasStyleBlock = true;
styleCode = name.slice(1, -1);
} else if (name === 'class') {
if (attr.value.type !== 'Literal' || typeof attr.value.value !== 'string') {
return;
}
lang = attr.value.value;
} else {
if (hasStyleBlock) {
transformHelper.context.addError(styleEl, 'Unsupported attribute on the component style tag: ' + attr.name);
return;
}
}
}
if (styleCode == null) {
return;
}
var context = transformHelper.context;
context.addDependency({
type: lang,
code: styleCode.trim(),
virtualPath: './'+path.basename(context.filename)+'.'+lang,
path: './'+path.basename(context.filename)
});
styleEl.detach();
}
function methodToProperty(method) {
return {
type: 'Property',
key: method.key,
computed: false,
value: method.value,
kind: 'init',
method: false,
shorthand: false
};
}
function classToObject(cls, el, transformHelper) {
return {
type: 'ObjectExpression',
properties: cls.body.body.map((method) => {
if(method.type != 'MethodDefinition') {
throw Error('Only methods are allowed on single file component class definitions.');
}
if (method.kind === 'method') {
return methodToProperty(method);
} else if (method.kind === 'constructor') {
transformHelper.context.deprecate('The constructor method should not be used for a component, use onCreate instead', el);
let converted = methodToProperty(method);
converted.key.name = 'onCreate';
return converted;
} else {
return method;
}
})
};
}
function handleClassDeclaration(classEl, transformHelper) {
let tree;
var wrappedSrc = '('+classEl.tagString+'\n)';
try {
tree = esprima.parse(wrappedSrc);
} catch(err) {
var message = 'Unable to parse JavaScript for component class. ' + err;
if (err.index != null) {
var errorIndex = err.index;
// message += '\n' + err.description;
if (errorIndex != null && errorIndex >= 0) {
transformHelper.context.addError({
pos: classEl.pos + errorIndex,
message: message
});
return;
}
}
transformHelper.context.addError(classEl, message);
return;
}
let expression = tree.body[0].expression;
if (expression.superClass && expression.superClass.name) {
transformHelper.context.addError(classEl, 'A component class is not allowed to use `extends`. See: https://github.com/marko-js/marko/wiki/Error:-Component-class-with-extends');
return;
}
let object = classToObject(expression, classEl, transformHelper);
let componentVar = transformHelper.context.addStaticVar('marko_component', escodegen.generate(object));
if (transformHelper.getRendererModule() != null) {
transformHelper.context.addError(classEl, 'The component has both an inline component `class` and a separate `component.js`. This is not allowed. See: https://github.com/marko-js/marko/wiki/Error:-Component-inline-and-external');
return;
}
var moduleInfo = {
inlineId: componentVar,
filename: transformHelper.filename,
requirePath: './' + path.basename(transformHelper.filename)
};
if (transformHelper.getComponentModule() == null) {
transformHelper.setComponentModule(moduleInfo);
}
transformHelper.setRendererModule(moduleInfo);
classEl.detach();
}
module.exports = function handleRootNodes() {
var context = this.context;
var builder = this.builder;
var componentFiles = getComponentFiles(context.filename);
if (!componentFiles) {
return;
}
var dirname = context.dirname;
componentFiles.styles.forEach((styleFile) => {
context.addDependency('./' + styleFile);
});
if (componentFiles.file) {
let file = componentFiles.file;
let moduleInfo = {
filename: path.join(dirname, file),
requirePath: './'+file.slice(0, file.lastIndexOf('.'))
};
this.setComponentModule(moduleInfo);
this.setRendererModule(moduleInfo);
}
if (componentFiles.browserFile) {
let file = componentFiles.browserFile;
this.setComponentModule({
filename: path.join(dirname, file),
requirePath: './' + file.slice(
0, file.lastIndexOf('.'))
});
}
var templateRoot = this.el;
var rootNodes = [];
var hasLegacyExplicitBind = false;
var hasIdCount = 0;
var nodeWithAssignedId;
var assignedId;
var transformHelper = this;
let walker = context.createWalker({
enter(node) {
var tagName = node.tagName && node.tagName.toLowerCase();
if (node.type === 'TemplateRoot' || !node.type) {
// Don't worry about the TemplateRoot or an Container node
} else if (node.type === 'HtmlElement') {
if (node.hasAttribute('w-bind')) {
transformHelper.setHasBoundComponentForTemplate();
hasLegacyExplicitBind = true;
} else {
if (node.hasAttribute('id')) {
hasIdCount++;
nodeWithAssignedId = node;
assignedId = node.getAttributeValue('id');
}
if (tagName === 'style') {
handleStyleElement(node, transformHelper);
} else {
rootNodes.push(node);
}
}
walker.skip();
return;
} else if (node.type === 'CustomTag') {
rootNodes.push(node);
walker.skip();
return;
} else {
if (tagName === 'class') {
handleClassDeclaration(node, transformHelper);
}
walker.skip();
return;
}
}
});
walker.walk(templateRoot);
if (hasLegacyExplicitBind) {
//There is an explicit bind so nothing to do
return;
}
if (!this.hasBoundComponentForTemplate()) {
return;
}
if (rootNodes.length === 0) {
return;
}
if (rootNodes.length > 1 && hasIdCount > 0) {
// We can only bind a component to multiple top-level elements if we can assign
// all of the IDs
return;
}
transformHelper.setHasBoundComponentForTemplate();
var nextKey = 0;
rootNodes.forEach((curNode, i) => {
curNode.setFlag('hasComponentBind');
if (!curNode.hasAttribute('key') && !curNode.hasAttribute('ref')) {
if (curNode.type === 'CustomTag' || rootNodes.length > 1) {
curNode.setAttributeValue('key', builder.literal('_r' + (nextKey++)));
}
}
});
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var ComponentArgs = require('./ComponentArgs');
var getRequirePath = require('../getRequirePath');
var MARKO_WIDGETS_VAR_KEY = Symbol('MARKO_WIDGETS_VAR');
var WIDGET_PROPS_KEY;
var HAS_COMPONENT_KEY = Symbol('HAS_WIDGET');
class TransformHelper {
constructor(el, context) {
this.el = el;
this.context = context;
this.builder = context.builder;
this.dirname = context.dirname;
this.filename = context.filename;
this.componentNextElId = 0;
this.componentArgs = undefined;
this.containingComponentNode = undefined;
this._markoComponentsVar = context.data.markoComponentsVar;
this.firstBind = false;
this.componentModule = null;
this.rendererModule = null;
}
setHasBoundComponentForTemplate() {
this.context.data[HAS_COMPONENT_KEY] = true;
}
setComponentModule(value) {
this.context.data.componentModule = value;
}
getComponentModule() {
return this.context.data.componentModule;
}
setRendererModule(value) {
this.context.data.rendererModule = value;
}
getRendererModule() {
return this.context.data.rendererModule;
}
getTemplateModule() {
return {
requirePath:this.context.getRequirePath(this.filename)
};
}
hasBoundComponentForTemplate() {
return this.context.data.componentModule != null ||
this.context.data[HAS_COMPONENT_KEY] ||
this.context.data[WIDGET_PROPS_KEY] != null;
}
getComponentProps() {
var componentProps = this.context.data[WIDGET_PROPS_KEY];
if (!componentProps) {
this.firstBind = true;
componentProps = this.context.data[WIDGET_PROPS_KEY] = {};
}
return componentProps;
}
addError(message, code) {
this.context.addError(this.el, message, code);
}
getComponentArgs() {
return this.componentArgs || (this.componentArgs = new ComponentArgs());
}
nextUniqueId() {
var componentNextElId = this.context.data.componentNextElId;
if (componentNextElId == null) {
this.context.data.componentNextElId = 0;
}
return (this.context.data.componentNextElId++);
}
getNestedIdExpression() {
this.assignComponentId();
return this.getComponentIdInfo().nestedIdExpression;
}
getIdExpression() {
this.assignComponentId();
return this.getComponentIdInfo().idExpression;
}
set componentIdInfo(value) {
this.el.data.componentIdInfo = value;
}
get componentIdInfo() {
return this.el.data.componentIdInfo;
}
getComponentIdInfo() {
return this.componentIdInfo;
}
getCompileContext() {
return this.context;
}
getMarkoComponentsRequirePath(target) {
return getRequirePath(target, this.context);
}
set markoComponentsVar(value) {
this.context.data[MARKO_WIDGETS_VAR_KEY] = value;
}
get markoComponentsVar() {
if (!this.context.data[MARKO_WIDGETS_VAR_KEY]) {
this.context.data[MARKO_WIDGETS_VAR_KEY] =
this.context.importModule(
'marko_components',
this.getMarkoComponentsRequirePath(this.isLegacyComponent ? 'marko/components/legacy' : 'marko/components'));
}
return this.context.data[MARKO_WIDGETS_VAR_KEY];
}
buildComponentElIdFunctionCall(id) {
var builder = this.builder;
var componentElId = builder.memberExpression(
builder.identifier('__component'),
builder.identifier('elId'));
return builder.functionCall(componentElId, arguments.length === 0 ? [] : [ id ]);
}
getTransformHelper(el) {
return new TransformHelper(el, this.context);
}
}
TransformHelper.prototype.assignComponentId = require('./assignComponentId');
TransformHelper.prototype.handleRootNodes = require('./handleRootNodes');
TransformHelper.prototype.handleIncludeNode = require('./handleIncludeNode');
TransformHelper.prototype.handleComponentEvents = require('./handleComponentEvents');
TransformHelper.prototype.handleComponentPreserve = require('./handleComponentPreserve');
TransformHelper.prototype.handleComponentPreserveAttrs = require('./handleComponentPreserveAttrs');
TransformHelper.prototype.handleComponentBind = require('./handleComponentBind');
TransformHelper.prototype.handleComponentFor = require('./handleComponentFor');
module.exports = TransformHelper;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| bindComponent.js | 33.33% | (2 / 6) | 100% | (0 / 0) | 0% | (0 / 3) | 33.33% | (2 / 6) | |
| componentArgs.js | 50% | (2 / 4) | 100% | (0 / 0) | 0% | (0 / 2) | 50% | (2 / 4) | |
| getCurrentComponent.js | 14.29% | (1 / 7) | 0% | (0 / 4) | 0% | (0 / 1) | 14.29% | (1 / 7) | |
| renderComponent.js | 25% | (1 / 4) | 100% | (0 / 0) | 0% | (0 / 1) | 25% | (1 / 4) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 1 1 | var createRendererFunc = require('../../renderer');
module.exports = function(componentProps) {
var renderer = createRendererFunc(
function(data, out, component, state) {
data.$renderBody(out, component, state);
},
componentProps,
null);
return function bindComponent(renderBody, out) {
renderer({
$renderBody: renderBody
}, out);
};
};
|
| 1 2 3 4 5 6 7 8 9 10 11 | 1 1 | var componentArgsHelper = module.exports = function componentArgsHelper( out, componentArgs) { out.data.$w = componentArgs; }; componentArgsHelper.cleanup = function(out) { delete out.data.$w; }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 1 | /**
* Helper method to return the ComponentDef for the current component being rendered.
* This is, it returns the component at the top of the component stack.
* @param {AsyncWriter} out The current rendering context that holds info about rendered components.
* @return {ComponentDef} The ComponentDef instance
*/
module.exports = function getCurrentComponent(out) {
var componentsContext = out.data.components;
var componentStack;
var len;
if (!componentsContext || (len = (componentStack = componentsContext.$__componentStack).length) < 2) {
throw Error('No component found');
}
return componentStack[len - 1];
};
|
| 1 2 3 4 5 6 7 | 1 | module.exports = function renderCompontent(tagRenderer, input, out, componentArgs) { out.$c = componentArgs; tagRenderer(input, out); out.$c = null; }; |
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| generateRegisterComponentCode.js | 17.24% | (5 / 29) | 0% | (0 / 10) | 0% | (0 / 1) | 17.24% | (5 / 29) | |
| getTransformHelper.js | 66.67% | (2 / 3) | 100% | (0 / 0) | 0% | (0 / 1) | 66.67% | (2 / 3) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | 1 1 1 1 1 | 'use strict';
const tryRequire = require('try-require');
const lassoModulesClientTransport = tryRequire('lasso-modules-client/transport', require);
const ok = require('assert').ok;
function generateRegisterComponentCode(componentModule, transformHelper, isSplit) {
ok(componentModule, '"componentModule" is required');
ok(transformHelper, '"transformHelper" is required');
ok(typeof componentModule.filename === 'string', '"componentModule.filename" should be a string');
ok(typeof transformHelper.dirname === 'string', '"transformHelper.dirname" should be a string');
let context = transformHelper.context;
let builder = context.builder;
let registerComponent = context.addStaticVar('marko_registerComponent',
builder.memberExpression(transformHelper.markoComponentsVar, builder.identifier('rc')));
let typeName = componentModule.filename;
var isLegacy = componentModule.legacy;
if (!isLegacy && !isSplit) {
typeName = transformHelper.filename;
}
if (lassoModulesClientTransport) {
typeName = lassoModulesClientTransport.getClientPath(typeName);
}
let def;
if (componentModule.legacy) {
// This if condition block should be deleted in Marko v5
let returnValue = builder.require(builder.literal(componentModule.requirePath));
let defineComponent = context.addStaticVar('marko_defineWidget',
builder.memberExpression(transformHelper.markoComponentsVar, builder.identifier('w')));
returnValue = builder.functionCall(defineComponent, [returnValue]);
def = builder.functionDeclaration(null, [] /* params */, [
builder.returnStatement(returnValue)
]);
} else if (isSplit) {
let returnValue = builder.require(builder.literal(componentModule.requirePath));
def = builder.functionDeclaration(null, [] /* params */, [
builder.returnStatement(returnValue)
]);
} else {
def = builder.functionDeclaration(null, [], [
builder.returnStatement(
builder.memberExpression(
builder.identifier('module'),
builder.identifier('exports')))
]);
}
return builder.functionCall(registerComponent, [
builder.literal(typeName),
def
]);
}
module.exports = generateRegisterComponentCode;
|
| 1 2 3 4 5 6 | 1 1 | var TransformHelper = require('../TransformHelper');
module.exports = function(el, context) {
return new TransformHelper(el, context);
};
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| empty.js | 66.67% | (2 / 3) | 100% | (0 / 0) | 0% | (0 / 1) | 66.67% | (2 / 3) | |
| notEmpty.js | 12.5% | (1 / 8) | 0% | (0 / 6) | 0% | (0 / 1) | 12.5% | (1 / 8) |
| 1 2 3 4 5 6 | 1 1 | var notEmpty = require('./notEmpty');
module.exports = function (o) {
return !notEmpty(o);
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 | 1 | module.exports = function notEmpty(o) { if (o == null) { return false; } else if (Array.isArray(o)) { return !!o.length; } else if (o === '') { return false; } return true; }; |
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 8.39% | (13 / 155) | 1.01% | (1 / 99) | 0% | (0 / 6) | 8.44% | (13 / 154) | |
| specialElHandlers.js | 5.71% | (2 / 35) | 0% | (0 / 23) | 0% | (0 / 5) | 5.71% | (2 / 35) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict'; var defaultDoc = typeof document == 'undefined' ? undefined : document; var specialElHandlers = require('./specialElHandlers'); var morphAttrs = require('../runtime/vdom/VElement').$__morphAttrs; var ELEMENT_NODE = 1; var TEXT_NODE = 3; var COMMENT_NODE = 8; function compareNodeNames(fromEl, toEl) { return fromEl.nodeName === toEl.$__nodeName; } function getElementById(doc, id) { return doc.getElementById(id); } function morphdom( fromNode, toNode, context, onNodeAdded, onBeforeElUpdated, onBeforeNodeDiscarded, onNodeDiscarded, onBeforeElChildrenUpdated ) { var doc = fromNode.ownerDocument || defaultDoc; // This object is used as a lookup to quickly find all keyed elements in the original DOM tree. var removalList = []; var foundKeys = {}; function walkDiscardedChildNodes(node) { onNodeDiscarded(node); var curChild = node.firstChild; while (curChild) { walkDiscardedChildNodes(curChild); curChild = curChild.nextSibling; } } function addVirtualNode(vEl, parentEl) { var realEl = vEl.$__actualize(doc); if (parentEl) { parentEl.appendChild(realEl); } onNodeAdded(realEl, context); var vCurChild = vEl.firstChild; while (vCurChild) { var realCurChild = null; var key = vCurChild.id; if (key) { var unmatchedFromEl = getElementById(doc, key); if (unmatchedFromEl && compareNodeNames(vCurChild, unmatchedFromEl)) { morphEl(unmatchedFromEl, vCurChild, false); realEl.appendChild(realCurChild = unmatchedFromEl); } } if (!realCurChild) { addVirtualNode(vCurChild, realEl); } vCurChild = vCurChild.nextSibling; } if (vEl.$__nodeType === 1) { var elHandler = specialElHandlers[vEl.nodeName]; if (elHandler !== undefined) { elHandler(realEl, vEl); } } return realEl; } function morphEl(fromEl, toEl, childrenOnly) { var toElKey = toEl.id; var nodeName = toEl.$__nodeName; if (childrenOnly === false) { if (toElKey) { // If an element with an ID is being morphed then it is will be in the final // DOM so clear it out of the saved elements collection foundKeys[toElKey] = true; } var constId = toEl.$__constId; if (constId !== undefined) { var otherProps = fromEl._vprops; if (otherProps !== undefined && constId === otherProps.c) { return; } } if (onBeforeElUpdated(fromEl, toElKey, context) === true) { return; } morphAttrs(fromEl, toEl); } if (onBeforeElChildrenUpdated(fromEl, toElKey, context) === true) { return; } if (nodeName !== 'TEXTAREA') { var curToNodeChild = toEl.firstChild; var curFromNodeChild = fromEl.firstChild; var curToNodeKey; var curFromNodeKey; var fromNextSibling; var toNextSibling; var matchingFromEl; outer: while (curToNodeChild) { toNextSibling = curToNodeChild.nextSibling; curToNodeKey = curToNodeChild.id; while (curFromNodeChild) { fromNextSibling = curFromNodeChild.nextSibling; curFromNodeKey = curFromNodeChild.id; var curFromNodeType = curFromNodeChild.nodeType; var isCompatible = undefined; if (curFromNodeType === curToNodeChild.$__nodeType) { if (curFromNodeType === ELEMENT_NODE) { // Both nodes being compared are Element nodes if (curToNodeKey) { // The target node has a key so we want to match it up with the correct element // in the original DOM tree if (curToNodeKey !== curFromNodeKey) { // The current element in the original DOM tree does not have a matching key so // let's check our lookup to see if there is a matching element in the original // DOM tree if ((matchingFromEl = getElementById(doc, curToNodeKey))) { if (curFromNodeChild.nextSibling === matchingFromEl) { // Special case for single element removals. To avoid removing the original // DOM node out of the tree (since that can break CSS transitions, etc.), // we will instead discard the current node and wait until the next // iteration to properly match up the keyed target element with its matching // element in the original tree isCompatible = false; } else { // We found a matching keyed element somewhere in the original DOM tree. // Let's moving the original DOM node into the current position and morph // it. // NOTE: We use insertBefore instead of replaceChild because we want to go through // the `removeNode()` function for the node that is being discarded so that // all lifecycle hooks are correctly invoked fromEl.insertBefore(matchingFromEl, curFromNodeChild); var curToNodeChildNextSibling = curToNodeChild.nextSibling; if (curToNodeChildNextSibling && curToNodeChildNextSibling.id === curFromNodeKey) { fromNextSibling = curFromNodeChild; } else { fromNextSibling = curFromNodeChild.nextSibling; removalList.push(curFromNodeChild); } curFromNodeChild = matchingFromEl; } } else { // The nodes are not compatible since the "to" node has a key and there // is no matching keyed node in the source tree isCompatible = false; } } } else if (curFromNodeKey) { // The original has a key isCompatible = false; } isCompatible = isCompatible !== false && compareNodeNames(curFromNodeChild, curToNodeChild) === true; if (isCompatible === true) { // We found compatible DOM elements so transform // the current "from" node to match the current // target DOM node. morphEl(curFromNodeChild, curToNodeChild, false); } } else if (curFromNodeType === TEXT_NODE || curFromNodeType === COMMENT_NODE) { // Both nodes being compared are Text or Comment nodes isCompatible = true; // Simply update nodeValue on the original node to // change the text value curFromNodeChild.nodeValue = curToNodeChild.nodeValue; } } if (isCompatible === true) { // Advance both the "to" child and the "from" child since we found a match curToNodeChild = toNextSibling; curFromNodeChild = fromNextSibling; continue outer; } // No compatible match so remove the old node from the DOM and continue trying to find a // match in the original DOM. However, we only do this if the from node is not keyed // since it is possible that a keyed node might match up with a node somewhere else in the // target tree and we don't want to discard it just yet since it still might find a // home in the final DOM tree. After everything is done we will remove any keyed nodes // that didn't find a home removalList.push(curFromNodeChild); curFromNodeChild = fromNextSibling; } // If we got this far then we did not find a candidate match for // our "to node" and we exhausted all of the children "from" // nodes. Therefore, we will just append the current "to" node // to the end if (curToNodeKey && (matchingFromEl = getElementById(doc, curToNodeKey)) && compareNodeNames(matchingFromEl, curToNodeChild)) { fromEl.appendChild(matchingFromEl); morphEl(matchingFromEl, curToNodeChild, false); } else { addVirtualNode(curToNodeChild, fromEl); } curToNodeChild = toNextSibling; curFromNodeChild = fromNextSibling; } // We have processed all of the "to nodes". If curFromNodeChild is // non-null then we still have some from nodes left over that need // to be removed while (curFromNodeChild) { removalList.push(curFromNodeChild); curFromNodeChild = curFromNodeChild.nextSibling; } } var specialElHandler = specialElHandlers[nodeName]; if (specialElHandler) { specialElHandler(fromEl, toEl); } } // END: morphEl(...) var morphedNode = fromNode; var fromNodeType = morphedNode.nodeType; var toNodeType = toNode.$__nodeType; var morphChildrenOnly = false; var shouldMorphEl = true; var newNode; // Handle the case where we are given two DOM nodes that are not // compatible (e.g. <div> --> <span> or <div> --> TEXT) if (fromNodeType == ELEMENT_NODE) { if (toNodeType == ELEMENT_NODE) { if (!compareNodeNames(fromNode, toNode)) { newNode = toNode.$__actualize(doc); morphChildrenOnly = true; removalList.push(fromNode); } } else { // Going from an element node to a text or comment node removalList.push(fromNode); newNode = toNode.$__actualize(doc); shouldMorphEl = false; } } else if (fromNodeType == TEXT_NODE || fromNodeType == COMMENT_NODE) { // Text or comment node if (toNodeType == fromNodeType) { morphedNode.nodeValue = toNode.nodeValue; return morphedNode; } else { // Text node to something else removalList.push(fromNode); newNode = addVirtualNode(toNode); shouldMorphEl = false; } } if (shouldMorphEl === true) { morphEl(newNode || morphedNode, toNode, morphChildrenOnly); } if (newNode) { if (fromNode.parentNode) { fromNode.parentNode.replaceChild(newNode, fromNode); } } // We now need to loop over any keyed nodes that might need to be // removed. We only do the removal if we know that the keyed node // never found a match. When a keyed node is matched up we remove // it out of fromNodesLookup and we use fromNodesLookup to determine // if a keyed node has been matched up or not for (var i=0, len=removalList.length; i<len; i++) { var node = removalList[i]; var key = node.id; if (!key || foundKeys[key] === undefined) { if (onBeforeNodeDiscarded(node) == false) { continue; } var parentNode = node.parentNode; if (parentNode) { parentNode.removeChild(node); } walkDiscardedChildNodes(node); } } return newNode || morphedNode; } module.exports = morphdom; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | 1 1 | function syncBooleanAttrProp(fromEl, toEl, name) { if (fromEl[name] !== toEl[name]) { fromEl[name] = toEl[name]; if (fromEl[name]) { fromEl.setAttribute(name, ''); } else { fromEl.removeAttribute(name, ''); } } } module.exports = { /** * Needed for IE. Apparently IE doesn't think that "selected" is an * attribute when reading over the attributes using selectEl.attributes */ OPTION: function(fromEl, toEl) { syncBooleanAttrProp(fromEl, toEl, 'selected'); }, /** * The "value" attribute is special for the <input> element since it sets * the initial value. Changing the "value" attribute without changing the * "value" property will have no effect since it is only used to the set the * initial value. Similar for the "checked" attribute, and "disabled". */ INPUT: function(fromEl, toEl) { syncBooleanAttrProp(fromEl, toEl, 'checked'); syncBooleanAttrProp(fromEl, toEl, 'disabled'); if (fromEl.value != toEl.value) { fromEl.value = toEl.value; } if (!toEl.$__hasAttribute('value')) { fromEl.removeAttribute('value'); } }, TEXTAREA: function(fromEl, toEl) { var newValue = toEl.value; if (fromEl.value != newValue) { fromEl.value = newValue; } var firstChild = fromEl.firstChild; if (firstChild) { // Needed for IE. Apparently IE sets the placeholder as the // node value and vise versa. This ignores an empty update. var oldValue = firstChild.nodeValue; if (oldValue == newValue || (!newValue && oldValue == fromEl.placeholder)) { return; } firstChild.nodeValue = newValue; } }, SELECT: function(fromEl, toEl) { if (!toEl.$__hasAttribute('multiple')) { var selectedIndex = -1; var i = 0; var curChild = toEl.firstChild; while(curChild) { if (curChild.$__nodeName == 'OPTION') { if (curChild.$__hasAttribute('selected')) { selectedIndex = i; break; } i++; } curChild = curChild.nextSibling; } fromEl.selectedIndex = i; } } }; |
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| RenderResult.js | 18.18% | (6 / 33) | 8.33% | (1 / 12) | 0% | (0 / 11) | 18.18% | (6 / 33) | |
| createOut.js | 85.71% | (6 / 7) | 100% | (0 / 0) | 50% | (1 / 2) | 85.71% | (6 / 7) | |
| dom-insert.js | 15.09% | (8 / 53) | 0% | (0 / 10) | 11.11% | (1 / 9) | 15.09% | (8 / 53) | |
| env-init.js | 91.67% | (11 / 12) | 62.5% | (5 / 8) | 100% | (1 / 1) | 91.67% | (11 / 12) | |
| events.js | 100% | (2 / 2) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (2 / 2) | |
| helper-forEachPropStatusVar.js | 11.11% | (2 / 18) | 100% | (0 / 0) | 0% | (0 / 6) | 11.11% | (2 / 18) | |
| helper-forEachProperty.js | 15.38% | (2 / 13) | 0% | (0 / 10) | 0% | (0 / 2) | 15.38% | (2 / 13) | |
| helper-forEachWithStatusVar.js | 16.67% | (3 / 18) | 0% | (0 / 4) | 0% | (0 / 6) | 16.67% | (3 / 18) | |
| helper-forRange.js | 11.11% | (1 / 9) | 0% | (0 / 6) | 0% | (0 / 1) | 11.11% | (1 / 9) | |
| helper-loadNestedTag.js | 12.5% | (1 / 8) | 0% | (0 / 4) | 0% | (0 / 2) | 12.5% | (1 / 8) | |
| helper-loadTemplate.js | 100% | (1 / 1) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (1 / 1) | |
| helper-merge.js | 33.33% | (2 / 6) | 0% | (0 / 4) | 0% | (0 / 1) | 33.33% | (2 / 6) | |
| helper-mergeNestedTags.js | 33.33% | (2 / 6) | 0% | (0 / 2) | 0% | (0 / 1) | 33.33% | (2 / 6) | |
| helpers.js | 19.61% | (10 / 51) | 0% | (0 / 33) | 0% | (0 / 10) | 19.61% | (10 / 51) | |
| index.js | 100% | (4 / 4) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (4 / 4) | |
| nextTick-browser.js | 5.56% | (1 / 18) | 0% | (0 / 11) | 0% | (0 / 2) | 5.56% | (1 / 18) | |
| nextTick.js | 100% | (1 / 1) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (1 / 1) | |
| renderable.js | 10.45% | (7 / 67) | 5.13% | (2 / 39) | 11.11% | (1 / 9) | 10.45% | (7 / 67) | |
| stream.js | 26.92% | (7 / 26) | 0% | (0 / 8) | 0% | (0 / 5) | 26.92% | (7 / 26) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | 1 1 1 1 1 1 | var domInsert = require('./dom-insert');
function getComponentDefs(result) {
var componentDefs = result.$__components;
if (!componentDefs) {
throw Error('No component');
}
return componentDefs;
}
function RenderResult(out) {
this.out = this.$__out = out;
this.$__components = undefined;
}
module.exports = RenderResult;
var proto = RenderResult.prototype = {
getComponent: function() {
return this.getComponents()[0];
},
getComponents: function(selector) {
if (this.$__components === undefined) {
throw Error('Not added to DOM');
}
var componentDefs = getComponentDefs(this);
var components = [];
componentDefs.forEach(function(componentDef) {
var component = componentDef.$__component;
if (!selector || selector(component)) {
components.push(component);
}
});
return components;
},
afterInsert: function(doc) {
var out = this.$__out;
var globalComponentsContext = out.global.components;
if (globalComponentsContext) {
this.$__components = globalComponentsContext.$__initComponents(doc);
} else {
this.$__components = null;
}
return this;
},
getNode: function(doc) {
return this.$__out.$__getNode(doc);
},
getOutput: function() {
return this.$__out.$__getOutput();
},
toString: function() {
return this.$__out.toString();
},
document: typeof document != 'undefined' && document
};
// Add all of the following DOM methods to Component.prototype:
// - appendTo(referenceEl)
// - replace(referenceEl)
// - replaceChildrenOf(referenceEl)
// - insertBefore(referenceEl)
// - insertAfter(referenceEl)
// - prependTo(referenceEl)
domInsert(
proto,
function getEl(renderResult, referenceEl) {
return renderResult.getNode(referenceEl.ownerDocument);
},
function afterInsert(renderResult, referenceEl) {
return renderResult.afterInsert(referenceEl.ownerDocument);
});
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 1 1 2 1 1 1 | var actualCreateOut;
function setCreateOut(createOutFunc) {
actualCreateOut = createOutFunc;
}
function createOut(globalData) {
return actualCreateOut(globalData);
}
createOut.$__setCreateOut = setCreateOut;
module.exports = createOut;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | 1 1 1 1 1 1 1 2 | var extend = require('raptor-util/extend');
var componentsUtil = require('../components/util');
var destroyComponentForEl = componentsUtil.$__destroyComponentForEl;
var destroyElRecursive = componentsUtil.$__destroyElRecursive;
function resolveEl(el) {
if (typeof el == 'string') {
var elId = el;
el = document.getElementById(elId);
if (!el) {
throw Error('Not found: ' + elId);
}
}
return el;
}
function beforeRemove(referenceEl) {
destroyElRecursive(referenceEl);
destroyComponentForEl(referenceEl);
}
module.exports = function(target, getEl, afterInsert) {
extend(target, {
appendTo: function(referenceEl) {
referenceEl = resolveEl(referenceEl);
var el = getEl(this, referenceEl);
referenceEl.appendChild(el);
return afterInsert(this, referenceEl);
},
prependTo: function(referenceEl) {
referenceEl = resolveEl(referenceEl);
var el = getEl(this, referenceEl);
referenceEl.insertBefore(el, referenceEl.firstChild || null);
return afterInsert(this, referenceEl);
},
replace: function(referenceEl) {
referenceEl = resolveEl(referenceEl);
var el = getEl(this, referenceEl);
beforeRemove(referenceEl);
referenceEl.parentNode.replaceChild(el, referenceEl);
return afterInsert(this, referenceEl);
},
replaceChildrenOf: function(referenceEl) {
referenceEl = resolveEl(referenceEl);
var el = getEl(this, referenceEl);
var curChild = referenceEl.firstChild;
while(curChild) {
var nextSibling = curChild.nextSibling; // Just in case the DOM changes while removing
if (curChild.nodeType == 1) {
beforeRemove(curChild);
}
curChild = nextSibling;
}
referenceEl.innerHTML = '';
referenceEl.appendChild(el);
return afterInsert(this, referenceEl);
},
insertBefore: function(referenceEl) {
referenceEl = resolveEl(referenceEl);
var el = getEl(this, referenceEl);
referenceEl.parentNode.insertBefore(el, referenceEl);
return afterInsert(this, referenceEl);
},
insertAfter: function(referenceEl) {
referenceEl = resolveEl(referenceEl);
var el = getEl(this, referenceEl);
el = el;
var nextSibling = referenceEl.nextSibling;
var parentNode = referenceEl.parentNode;
if (nextSibling) {
parentNode.insertBefore(el, nextSibling);
} else {
parentNode.appendChild(el);
}
return afterInsert(this, referenceEl);
}
});
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 1 1 1 1 1 1 1 1 1 1 1 | require('./stream');
require('./dependencies/html');
Eif (!process.env.BUNDLE) {
Iif (process.env.MARKO_HOT_RELOAD) {
require('../hot-reload').enable();
}
// If process was launched with browser refresh then automatically
// enable browser-refresh
require('../browser-refresh').enable();
}
function fixFlush() {
try {
var OutgoingMessage = require('http').OutgoingMessage;
Eif (OutgoingMessage.prototype.flush && OutgoingMessage.prototype.flush.toString().indexOf('deprecated') !== -1) {
// Yes, we are monkey-patching http. This method should never have been added and it was introduced on
// the iojs fork. It was quickly deprecated and I'm 99% sure no one is actually using it.
// See:
// - https://github.com/marko-js/async-writer/issues/3
// - https://github.com/nodejs/node/issues/2920
//
// This method causes problems since marko looks for the flush method and calls it found.
// The `res.flush()` method is introduced by the [compression](https://www.npmjs.com/package/compression)
// middleware, but, otherwise, it should typically not exist.
delete require('http').OutgoingMessage.prototype.flush;
}
} catch(e) {}
}
fixFlush();
|
| 1 2 3 | 1 1 | var EventEmitter = require('events-light');
module.exports = new EventEmitter();
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 1 1 | 'use strict'; function LoopStatus(getLength, isLast, isFirst, getIndex) { this.getLength = getLength; this.isLast = isLast; this.isFirst = isFirst; this.getIndex = getIndex; } module.exports = function forEachPropStatusVarHelper(object, callback) { var keys = Object.keys(object); var i = 0; var len = keys.length; var loopStatus = new LoopStatus( function getLength() { return len; }, function isLast() { return i === len - 1; }, function isFirst() { return i === 0; }, function getIndex() { return i; }); for (; i < len; i++) { var key = keys[i]; var value = object[key]; callback(key, value, loopStatus); } }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 1 1 | var isArray = Array.isArray; /** * Internal helper method for looping over the properties of any object * @private */ module.exports = function forEachPropertyHelper(o, func) { if (!o) { return; } if (isArray(o)) { for (var i=0; i<o.length; i++) { func(i, o[i]); } } else if (typeof Map && o instanceof Map) { o.forEach(function(v, k) { func(k, v); }); } else { for (var k in o) { if (o.hasOwnProperty(k)) { func(k, o[k]); } } } }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 1 1 1 | function LoopStatus(len) { this.i = 0; this.len = len; } LoopStatus.prototype = { getLength: function() { return this.len; }, isLast: function() { return this.i === this.len - 1; }, isFirst: function() { return this.i === 0; }, getIndex: function() { return this.i; } }; /** * Internal helper method to handle loops with a status variable * @private */ module.exports = function forEachStatusVariableHelper(array, callback) { if (!array) { return; } if (!array.forEach) { array = [array]; } var len = array.length; var loopStatus = new LoopStatus(len); for (; loopStatus.i < len; loopStatus.i++) { var o = array[loopStatus.i]; callback(o, loopStatus); } }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 1 | module.exports = function forRangeHelper(from, to, step, callback) { if (step == null) { step = from <= to ? 1 : -1; } var i; if (step > 0) { for (i=from; i<=to; i += step) { callback(i); } } else { for (i=from; i>=to; i += step) { callback(i); } } }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 1 | module.exports = function loadNestedTagHelper(targetProperty, isRepeated) { return function(input, parent) { // If we are nested tag then we do not have a renderer if (isRepeated) { var existingArray = parent[targetProperty]; if (existingArray) { existingArray.push(input); } else { parent[targetProperty] = [input]; } } else { parent[targetProperty] = input; } }; }; |
| 1 2 3 4 5 | 1 | /**
* Loads a template
*/
module.exports = require('./loader');
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 1 1 | /**
* Merges object properties
* @param {[type]} object [description]
* @param {[type]} source [description]
* @return {[type]} [description]
*/
function merge(into, source) {
for (var k in source) {
if (source.hasOwnProperty(k) && !into.hasOwnProperty(k)) {
into[k] = source[k];
}
}
return into;
}
module.exports = merge;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 1 1 | /**
* Merges nested tags by rendering the body
* @param {[type]} object [description]
* @param {[type]} source [description]
* @return {[type]} [description]
*/
function mergeNestedTags(input) {
if (input.renderBody) {
input.renderBody(null, input);
}
input.renderBody = null;
return input;
}
module.exports = mergeNestedTags;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | 1 1 1 1 1 1 1 1 1 1 | 'use strict'; var isArray = Array.isArray; function isFunction(arg) { return typeof arg == 'function'; } function classList(arg, classNames) { var len; if (arg) { if (typeof arg == 'string') { if (arg) { classNames.push(arg); } } else if (typeof (len = arg.length) == 'number') { for (var i=0; i<len; i++) { classList(arg[i], classNames); } } else if (typeof arg == 'object') { for (var name in arg) { if (arg.hasOwnProperty(name)) { var value = arg[name]; if (value) { classNames.push(name); } } } } } } function createDeferredRenderer(handler) { function deferredRenderer(input, out) { deferredRenderer.renderer(input, out); } // This is the initial function that will do the rendering. We replace // the renderer with the actual renderer func on the first render deferredRenderer.renderer = function(input, out) { var rendererFunc = handler.renderer || handler._ || handler.render; if (!isFunction(rendererFunc)) { throw Error('Invalid renderer'); } // Use the actual renderer from now on deferredRenderer.renderer = rendererFunc; rendererFunc(input, out); }; return deferredRenderer; } function resolveRenderer(handler) { var renderer = handler.renderer || handler._; if (renderer) { return renderer; } if (isFunction(handler)) { return handler; } // If the user code has a circular function then the renderer function // may not be available on the module. Since we can't get a reference // to the actual renderer(input, out) function right now we lazily // try to get access to it later. return createDeferredRenderer(handler); } /** * Internal helper method to prevent null/undefined from being written out * when writing text that resolves to null/undefined * @private */ exports.s = function strHelper(str) { return (str == null) ? '' : str.toString(); }; /** * Internal helper method to handle loops without a status variable * @private */ exports.f = function forEachHelper(array, callback) { if (isArray(array)) { for (var i=0; i<array.length; i++) { callback(array[i]); } } else if (isFunction(array)) { // Also allow the first argument to be a custom iterator function array(callback); } }; /** * Helper to load a custom tag */ exports.t = function loadTagHelper(renderer, targetProperty, isRepeated) { if (renderer) { renderer = resolveRenderer(renderer); } return renderer; }; /** * classList(a, b, c, ...) * Joines a list of class names with spaces. Empty class names are omitted. * * classList('a', undefined, 'b') --> 'a b' * */ exports.cl = function classListHelper() { var classNames = []; classList(arguments, classNames); return classNames.join(' '); }; |
| 1 2 3 4 5 6 7 | 1 1 1 1 | 'use strict';
require('./env-init'); // no-op in the browser, but enables extra features on the server
exports.createOut = require('./createOut');
exports.load = require('./loader');
exports.events = require('./events');
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 2 | /* globals window */ var win = window; var setImmediate = win.setImmediate; if (!setImmediate) { if (win.postMessage) { var queue = []; var messageName = 'si'; win.addEventListener('message', function (event) { var source = event.source; if (source == win || !source && event.data === messageName) { event.stopPropagation(); if (queue.length > 0) { var fn = queue.shift(); fn(); } } }, true); setImmediate = function(fn) { queue.push(fn); win.postMessage(messageName, '*'); }; } else { setImmediate = setTimeout; } } module.exports = setImmediate; |
| 1 2 3 | 1 | module.exports = process.nextTick; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | 1 1 1 1 2 2 2 | var defaultCreateOut = require('./createOut');
var extend = require('raptor-util/extend');
function safeRender(renderFunc, finalData, finalOut, shouldEnd) {
try {
renderFunc(finalData, finalOut);
if (shouldEnd) {
finalOut.end();
}
} catch(err) {
var actualEnd = finalOut.end;
finalOut.end = function() {};
setTimeout(function() {
finalOut.end = actualEnd;
finalOut.error(err);
}, 0);
}
return finalOut;
}
module.exports = function(target, renderer) {
var renderFunc = renderer && (renderer.renderer || renderer.render || renderer);
var createOut = target.createOut || renderer.createOut || defaultCreateOut;
return extend(target, {
createOut: createOut,
renderToString: function(data, callback) {
var localData = data || {};
var render = renderFunc || this._;
var globalData = localData.$global;
var out = createOut(globalData);
out.global.template = this;
if (globalData) {
localData.$global = undefined;
}
if (callback) {
out.on('finish', function() {
callback(null, out.toString(), out);
})
.once('error', callback);
return safeRender(render, localData, out, true);
} else {
out.sync();
render(localData, out);
return out.toString();
}
},
renderSync: function(data) {
var localData = data || {};
var render = renderFunc || this._;
var globalData = localData.$global;
var out = createOut(globalData);
out.sync();
out.global.template = this;
if (globalData) {
localData.$global = undefined;
}
render(localData, out);
return out.$__getResult();
},
/**
* Renders a template to either a stream (if the last
* argument is a Stream instance) or
* provides the output to a callback function (if the last
* argument is a Function).
*
* Supported signatures:
*
* render(data)
* render(data, out)
* render(data, stream)
* render(data, callback)
*
* @param {Object} data The view model data for the template
* @param {AsyncStream/AsyncVDOMBuilder} out A Stream, an AsyncStream/AsyncVDOMBuilder instance, or a callback function
* @return {AsyncStream/AsyncVDOMBuilder} Returns the AsyncStream/AsyncVDOMBuilder instance that the template is rendered to
*/
render: function(data, out) {
var callback;
var finalOut;
var finalData;
var globalData;
var render = renderFunc || this._;
var shouldBuffer = this.$__shouldBuffer;
var shouldEnd = true;
if (data) {
finalData = data;
if ((globalData = data.$global)) {
finalData.$global = undefined;
}
} else {
finalData = {};
}
if (out && out.$__isOut) {
finalOut = out;
shouldEnd = false;
extend(out.global, globalData);
} else if (typeof out == 'function') {
finalOut = createOut(globalData);
callback = out;
} else {
finalOut = createOut(
globalData, // global
out, // writer(AsyncStream) or parentNode(AsyncVDOMBuilder)
null, // state
shouldBuffer // ignored by AsyncVDOMBuilder
);
}
if (callback) {
finalOut
.on('finish', function() {
callback(null, finalOut.$__getResult());
})
.once('error', callback);
}
globalData = finalOut.global;
globalData.template = globalData.template || this;
return safeRender(render, finalData, finalOut, shouldEnd);
}
});
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | 1 1 1 1 1 1 1 | 'use strict';
/*
This module is used to monkey patch `Template.prototype` to add a new `stream(templateData)` method. Since
this module is likely not needed in the browser, we have split out the code into a separate module. This module
is always loaded on the server, but if you need streaming in the browser you must add the following
line to your app:
require('marko/stream');
*/
var stream = require('stream');
var Template = require('./html/Template');
var AsyncStream = require('./html/AsyncStream');
function Readable(template, data, options) {
Readable.$super.call(this);
this._t = template;
this._d = data;
this._shouldBuffer = !options || options.shouldBuffer !== false;
this._rendered = false;
}
Readable.prototype = {
write: function(data) {
if (data != null) {
this.push(data);
}
},
end: function() {
this.push(null);
},
_read: function() {
if (this._rendered) {
return;
}
this._rendered = true;
var template = this._t;
var data = this._d;
var globalData = data && data.$global;
var shouldBuffer = this._shouldBuffer;
var out = new AsyncStream(globalData, this, null, shouldBuffer);
template.render(data, out);
out.end();
}
};
require('raptor-util/inherit')(Readable, stream.Readable);
Template.prototype.stream = function(data) {
return new Readable(this, data, this._options);
};
|
| 1 2 3 4 5 | 1 1 1 | var patch = require('./').patch;
var Template = require('../html/Template');
patch(Template);
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | var path = require('path');
var defaultResolveFrom = require('resolve-from');
var env = process.env.NODE_ENV;
var production = !env || env !== 'development';
function getDeps(template, context) {
if (!template.meta && template.template) {
template = template.template;
}
if (typeof template.createOut !== 'function') {
return [];
}
if (production && template.deps) {
return template.deps;
}
var deps = template.deps = [];
if (!template.meta) {
console.error('Metadata not set for template at ', template.path);
return [];
}
var meta = template.meta;
var root = path.dirname(template.path);
if (meta.tags) {
meta.tags.forEach(tagPath => {
var resolveFrom = context.resolveFrom || defaultResolveFrom;
var tag = resolveFrom(root, tagPath);
var ext = path.extname(tag);
var req = context.require || require;
try {
tag = req.resolve(tag.slice(0, 0 - ext.length) + '.js');
} catch(e) {}
var tagDeps = getDeps(req(tag), context);
deps.push.apply(deps, tagDeps);
});
}
if (meta.deps) {
deps.push.apply(deps, meta.deps.map(d => resolveDep(d, root, context)));
}
template.deps = dedupeDeps(deps);
return deps;
}
function resolveDep(dep, root, context) {
if (typeof dep === 'string') {
dep = parseDependencyString(dep);
}
if (dep.path) {
var resolveFrom = (context && context.resolveFrom) || defaultResolveFrom;
dep.path = resolveFrom(root, dep.path);
if(dep.path && !dep.type) {
dep.type = dep.path.slice(dep.path.lastIndexOf('.')+1);
}
}
if (dep.virtualPath) {
dep.virtualPath = path.resolve(root, dep.virtualPath);
}
return dep;
}
function parseDependencyString(string) {
var match = /^(?:([\w-]+)(?:\:\s*|\s+))?(.*?(?:\.(\w+))?)$/.exec(string);
return {
type: match[1] || match[3],
path: match[2]
};
}
function dedupeDeps(deps) {
return deps;
}
function patch(Template) {
Template.prototype.getDependencies = function(context) {
context = context || {};
return getDeps(this, context);
};
}
exports.getDeps = getDeps;
exports.resolveDep = resolveDep;
exports.patch = patch;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| AsyncStream.js | 6.93% | (16 / 231) | 2.97% | (3 / 101) | 0% | (0 / 36) | 6.93% | (16 / 231) | |
| BufferedWriter.js | 20% | (3 / 15) | 0% | (0 / 6) | 0% | (0 / 5) | 20% | (3 / 15) | |
| StringWriter.js | 42.86% | (3 / 7) | 100% | (0 / 0) | 0% | (0 / 3) | 42.86% | (3 / 7) | |
| Template.js | 53.85% | (7 / 13) | 0% | (0 / 2) | 0% | (0 / 3) | 53.85% | (7 / 13) | |
| escape.js | 48.15% | (13 / 27) | 0% | (0 / 15) | 0% | (0 / 5) | 48.15% | (13 / 27) | |
| helper-attr.js | 33.33% | (7 / 21) | 0% | (0 / 14) | 0% | (0 / 1) | 33.33% | (7 / 21) | |
| helper-attrs.js | 27.27% | (3 / 11) | 0% | (0 / 4) | 0% | (0 / 1) | 27.27% | (3 / 11) | |
| helper-createInlineTemplate.js | 66.67% | (2 / 3) | 100% | (0 / 0) | 0% | (0 / 1) | 66.67% | (2 / 3) | |
| helpers.js | 36.92% | (24 / 65) | 0% | (0 / 41) | 0% | (0 / 5) | 36.92% | (24 / 65) | |
| index.js | 78.57% | (11 / 14) | 100% | (0 / 0) | 0% | (0 / 3) | 78.57% | (11 / 14) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var EventEmitter = require('events-light');
var StringWriter = require('./StringWriter');
var BufferedWriter = require('./BufferedWriter');
var defaultDocument = typeof document != 'undefined' && document;
var RenderResult = require('../RenderResult');
var attrsHelper = require('./helper-attrs');
var escapeXml = require('./escape').escapeXml;
var voidWriter = { write:function(){} };
function State(root, stream, writer, events) {
this.root = root;
this.stream = stream;
this.writer = writer;
this.events = events;
this.remaining = 0;
this.lastCount = 0;
this.last = undefined; // Array
this.ended = false;
this.finished = false;
this.ids = 0;
}
function AsyncStream(global, writer, state, shouldBuffer) {
var finalGlobal = this.attributes = global || {};
var originalStream;
if (state) {
originalStream = state.stream;
} else {
var events = finalGlobal.events /* deprecated */ = writer && writer.on ? writer : new EventEmitter();
if (writer) {
originalStream = writer;
if (shouldBuffer) {
writer = new BufferedWriter(writer);
}
} else {
writer = originalStream = new StringWriter();
}
state = new State(this, originalStream, writer, events);
}
this.global = finalGlobal;
this.stream = originalStream;
this._state = state;
this.data = {};
this.writer = writer;
writer.stream = this;
this._sync = false;
this._stack = undefined;
this.name = undefined;
this._timeoutId = undefined;
this._node = undefined;
this._elStack = undefined; // Array
this.$c = null; // Component args
}
AsyncStream.DEFAULT_TIMEOUT = 10000;
AsyncStream.INCLUDE_STACK = typeof process !== 'undefined' && process.env.NODE_ENV === 'development';
AsyncStream.enableAsyncStackTrace = function() {
AsyncStream.INCLUDE_STACK = true;
};
var proto = AsyncStream.prototype = {
constructor: AsyncStream,
$__document: defaultDocument,
$__isOut: true,
sync: function() {
this._sync = true;
},
isSync: function() {
return this._sync === true;
},
write: function(str) {
if (str != null) {
this.writer.write(str.toString());
}
return this;
},
$__getOutput: function() {
return this._state.writer.toString();
},
/**
* Legacy...
*/
getOutput: function() {
return this.$__getOutput();
},
toString: function() {
return this._state.writer.toString();
},
$__getResult: function() {
this._result = this._result || new RenderResult(this);
return this._result;
},
beginAsync: function(options) {
if (this._sync) {
throw new Error('beginAsync() not allowed when using renderSync()');
}
var state = this._state;
var currentWriter = this.writer;
/* ┏━━━━━┓ this
┃ WAS ┃ ↓↑
┗━━━━━┛ prevWriter → currentWriter → nextWriter */
var newWriter = new StringWriter();
var newStream = new AsyncStream(this.global, currentWriter, state);
this.writer = newWriter;
newWriter.stream = this;
newWriter.next = currentWriter.next;
currentWriter.next = newWriter;
/* ┏━━━━━┓ newStream this
┃ NOW ┃ ↓↑ ↓↑
┗━━━━━┛ prevWriter → currentWriter → newWriter → nextWriter */
var timeout;
var name;
state.remaining++;
if (options != null) {
if (typeof options === 'number') {
timeout = options;
} else {
timeout = options.timeout;
if (options.last === true) {
if (timeout == null) {
// Don't assign a timeout to last flush fragments
// unless it is explicitly given a timeout
timeout = 0;
}
state.lastCount++;
}
name = options.name;
}
}
if (timeout == null) {
timeout = AsyncStream.DEFAULT_TIMEOUT;
}
newStream.stack = AsyncStream.INCLUDE_STACK ? new Error().stack : null;
newStream.name = name;
if (timeout > 0) {
newStream._timeoutId = setTimeout(function() {
newStream.error(new Error('Async fragment ' + (name ? '(' + name + ') ': '') + 'timed out after ' + timeout + 'ms'));
}, timeout);
}
state.events.emit('beginAsync', {
writer: newStream, // Legacy
parentWriter: this, // Legacy
out: newStream,
parentOut: this
});
return newStream;
},
end: function(data) {
if (data) {
this.write(data);
}
var currentWriter = this.writer;
/* ┏━━━━━┓ this nextStream
┃ WAS ┃ ↓↑ ↓↑
┗━━━━━┛ currentWriter → nextWriter → futureWriter */
// Prevent any more writes to the current steam
this.writer = voidWriter;
currentWriter.stream = null;
// Flush the contents of nextWriter to the currentWriter
this.flushNext(currentWriter);
/* ┏━━━━━┓ this ╵ nextStream
┃ ┃ ↓ ╵ ↓↑
┃ NOW ┃ voidWriter ╵ currentWriter → futureWriter
┃ ┃ ──────────────┴────────────────────────────────
┗━━━━━┛ Flushed & garbage collected: nextWriter */
var state = this._state;
if (state.finished) {
return;
}
var remaining;
if (this === state.root) {
remaining = state.remaining;
state.ended = true;
} else {
var timeoutId = this._timeoutId;
if (timeoutId) {
clearTimeout(timeoutId);
}
remaining = --state.remaining;
}
if (state.ended) {
if (!state.lastFired && (state.remaining - state.lastCount === 0)) {
state.lastFired = true;
state.lastCount = 0;
state.events.emit('last');
}
if (remaining === 0) {
state.finished = true;
if (state.writer.end) {
state.writer.end();
} else {
state.events.emit('finish', this.$__getResult());
}
}
}
return this;
},
// flushNextOld: function(currentWriter) {
// if (currentWriter === this._state.writer) {
// var nextStream;
// var nextWriter = currentWriter.next;
//
// // flush until there is no nextWriter
// // or the nextWriter is still attached
// // to a branch.
// while(nextWriter) {
// currentWriter.write(nextWriter.toString());
// nextStream = nextWriter.stream;
//
// if(nextStream) break;
// else nextWriter = nextWriter.next;
// }
//
// // Orphan the nextWriter and everything that
// // came before it. They have been flushed.
// currentWriter.next = nextWriter && nextWriter.next;
//
// // If there is a nextStream,
// // set its writer to currentWriter
// // (which is the state.writer)
// if(nextStream) {
// nextStream.writer = currentWriter;
// currentWriter.stream = nextStream;
// }
// }
// },
flushNext: function(currentWriter) {
// It is possible that currentWriter is the
// last writer in the chain, so let's make
// sure there is a nextWriter to flush.
var nextWriter = currentWriter.next;
if (nextWriter) {
// Flush the contents of nextWriter
// to the currentWriter
currentWriter.write(nextWriter.toString());
// Remove nextWriter from the chain.
// It has been flushed and can now be
// garbage collected.
currentWriter.next = nextWriter.next;
// It's possible that nextWriter is the last
// writer in the chain and its stream already
// ended, so let's make sure nextStream exists.
var nextStream = nextWriter.stream;
if (nextStream) {
// Point the nextStream to currentWriter
nextStream.writer = currentWriter;
currentWriter.stream = nextStream;
}
}
},
on: function(event, callback) {
var state = this._state;
if (event === 'finish' && state.finished) {
callback(this.$__getResult());
return this;
}
state.events.on(event, callback);
return this;
},
once: function(event, callback) {
var state = this._state;
if (event === 'finish' && state.finished) {
callback(this.$__getResult());
return this;
}
state.events.once(event, callback);
return this;
},
onLast: function(callback) {
var state = this._state;
var lastArray = state.last;
if (!lastArray) {
lastArray = state.last = [];
var i = 0;
var next = function next() {
if (i === lastArray.length) {
return;
}
var _next = lastArray[i++];
_next(next);
};
this.once('last', function() {
next();
});
}
lastArray.push(callback);
return this;
},
emit: function(type, arg) {
var events = this._state.events;
switch(arguments.length) {
case 1:
events.emit(type);
break;
case 2:
events.emit(type, arg);
break;
default:
events.emit.apply(events, arguments);
break;
}
return this;
},
removeListener: function() {
var events = this._state.events;
events.removeListener.apply(events, arguments);
return this;
},
prependListener: function() {
var events = this._state.events;
events.prependListener.apply(events, arguments);
return this;
},
pipe: function(stream) {
this._state.stream.pipe(stream);
return this;
},
error: function(e) {
var stack = this._stack;
var name = this.name;
var message;
if (name) {
message = 'Render async fragment error (' + name + ')';
} else {
message = 'Render error';
}
message += '. Exception: ' + (e.stack || e);
if (stack) {
message += '\nCreation stack trace: ' + stack;
}
e = new Error(message);
try {
this.emit('error', e);
} finally {
// If there is no listener for the error event then it will
// throw a new here. In order to ensure that the async fragment
// is still properly ended we need to put the end() in a `finally`
// block
this.end();
}
if (console) {
console.error(message);
}
return this;
},
flush: function() {
var state = this._state;
if (!state.finished) {
var writer = state.writer;
if (writer && writer.flush) {
writer.flush();
}
}
return this;
},
createOut: function() {
return new AsyncStream(this.global);
},
element: function(tagName, elementAttrs, openTagOnly) {
var str = '<' + tagName +
attrsHelper(elementAttrs) +
'>';
if (openTagOnly !== true) {
str += '</' + tagName + '>';
}
this.write(str);
},
beginElement: function(name, elementAttrs) {
var str = '<' + name +
attrsHelper(elementAttrs) +
'>';
this.write(str);
if (this._elStack) {
this._elStack.push(name);
} else {
this._elStack = [name];
}
},
endElement: function() {
var tagName = this._elStack.pop();
this.write('</' + tagName + '>');
},
text: function(str) {
this.write(escapeXml(str));
},
$__getNode: function(doc) {
var node = this._node;
var curEl;
var newBodyEl;
var html = this.$__getOutput();
if (!doc) {
doc = this.$__document;
}
if (!node) {
if (html) {
newBodyEl = doc.createElement('body');
newBodyEl.innerHTML = html;
if (newBodyEl.childNodes.length == 1) {
// If the rendered component resulted in a single node then just use that node
node = newBodyEl.childNodes[0];
} else {
// Otherwise, wrap the nodes in a document fragment node
node = doc.createDocumentFragment();
while ((curEl = newBodyEl.firstChild)) {
node.appendChild(curEl);
}
}
} else {
// empty HTML so use empty document fragment (so that we're returning a valid DOM node)
node = doc.createDocumentFragment();
}
this._node = node;
}
return node;
},
then: function(fn, fnErr) {
var out = this;
var promise = new Promise(function(resolve, reject) {
out.on('error', reject);
out.on('finish', function(result) {
resolve(result);
});
});
return Promise.resolve(promise).then(fn, fnErr);
},
catch: function(fnErr) {
return this.then(undefined, fnErr);
}
};
// alias:
proto.w = proto.write;
module.exports = AsyncStream;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 1 1 1 | 'use strict'; /** * Simple wrapper that can be used to wrap a stream * to reduce the number of write calls. In Node.js world, * each stream.write() becomes a chunk. We can avoid overhead * by reducing the number of chunks by buffering the output. */ function BufferedWriter(wrappedStream) { this._buffer = ''; this._wrapped = wrappedStream; } BufferedWriter.prototype = { write: function(str) { this._buffer += str; }, flush: function() { if (this._buffer.length !== 0) { this._wrapped.write(this._buffer); this._buffer = ''; if (this._wrapped.flush) { this._wrapped.flush(); } } }, end: function() { this.flush(); if (!this._wrapped.isTTY) { this._wrapped.end(); } }, clear: function() { this._buffer = ''; } }; module.exports = BufferedWriter; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 1 1 1 | 'use strict'; function StringWriter() { this.str = ''; } StringWriter.prototype = { write: function(str) { this.str += str; return this; }, /** * Converts the string buffer into a String. * * @returns {String} The built String */ toString: function() { return this.str; } }; module.exports = StringWriter; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 1 1 1 1 1 1 1 | 'use strict';
var AsyncStream = require('./AsyncStream');
var makeRenderable = require('../renderable');
function Template(path, renderFunc, options) {
this.path = path;
this._ = renderFunc;
this.$__shouldBuffer = !options || options.shouldBuffer !== false;
this.meta = undefined;
}
function createOut(globalData, parent, state, buffer) {
return new AsyncStream(globalData, parent, state, buffer);
}
Template.prototype = {
createOut: createOut,
stream: function() {
throw new Error('You must require("marko/stream")');
}
};
makeRenderable(Template.prototype);
module.exports = Template;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | var elTest = /[&<]/;
var elTestReplace = /[&<]/g;
var attrTest = /[&<\"\n]/;
var attrReplace = /[&<\"\n]/g;
var replacements = {
'<': '<',
'&': '&',
'"': '"',
'\'': ''',
'\n': ' ' //Preserve new lines so that they don't get normalized as space
};
function replaceChar(match) {
return replacements[match];
}
function escapeString(str, regexpTest, regexpReplace) {
return regexpTest.test(str) ? str.replace(regexpReplace, replaceChar) : str;
}
function escapeXmlHelper(value, regexpTest, regexpReplace) {
// check for most common case first
if (typeof value === 'string') {
return escapeString(value, regexpTest, regexpReplace);
} else if (value == null) {
return '';
} else if (typeof value === 'object') {
if (value.toHTML) {
return value.toHTML();
}
} else if (value === true || value === false || typeof value === 'number') {
return value.toString();
}
return escapeString(value.toString(), regexpTest, regexpReplace);
}
function escapeXml(value) {
return escapeXmlHelper(value, elTest, elTestReplace);
}
function escapeXmlAttr(value) {
return escapeXmlHelper(value, attrTest, attrReplace);
}
exports.escapeString = escapeString;
exports.escapeXml = escapeXml;
exports.escapeXmlAttr = escapeXmlAttr;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 1 1 1 1 1 1 1 | var escape = require('./escape');
var escapeString = escape.escapeString;
var escapeXmlAttr = escape.escapeXmlAttr;
var stringifiedAttrTest = /[&\'\n]/;
var stringifiedAttrReplace = /[&\'\n]/g;
function attr(name, value, shouldEscape) {
shouldEscape = shouldEscape !== false;
var type = typeof value;
if (type === 'string') {
return ' ' + name + '="' + (shouldEscape ? escapeXmlAttr(value) : value) + '"';
} else if (value === true) {
return ' ' + name;
} else if (value == null || value === false) {
return '';
} else if (type === 'object') {
value = JSON.stringify(value);
if (shouldEscape) {
value = escapeString(value, stringifiedAttrTest, stringifiedAttrReplace);
}
return ' ' + name + "='" + value + "'";
} else {
return ' ' + name + '=' + value; // number (doesn't need quotes)
}
}
module.exports = attr;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 1 1 1 | var attrHelper = require('./helper-attr');
function attrs(arg) {
if (typeof arg === 'object') {
var out = '';
for (var attrName in arg) {
out += attrHelper(attrName, arg[attrName]);
}
return out;
} else if (typeof arg === 'string') {
return arg;
}
return '';
}
module.exports = attrs;
|
| 1 2 3 4 5 6 | 1 1 | var Template = require('./Template');
module.exports = function(path, renderFunc) {
return new Template(path, renderFunc);
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var extend = require('raptor-util/extend');
var STYLE_ATTR = 'style';
var CLASS_ATTR = 'class';
var escape = require('./escape');
var escapeXml = escape.escapeXml;
var escapeXmlAttr = escape.escapeXmlAttr;
var attrHelper = require('./helper-attr');
var attrsHelper = require('./helper-attrs');
var classList;
/**
* Internal method to escape special XML characters
* @private
*/
exports.x = escapeXml;
/**
* Internal method to escape special XML characters within an attribute
* @private
*/
exports.xa = escapeXmlAttr;
/**
* Escapes the '</' sequence in the body of a <script> body to avoid the `<script>` being
* ended prematurely.
*
* For example:
* var evil = {
* name: '</script><script>alert(1)</script>'
* };
*
* <script>var foo = ${JSON.stringify(evil)}</script>
*
* Without escaping the ending '</script>' sequence the opening <script> tag would be
* prematurely ended and a new script tag could then be started that could then execute
* arbitrary code.
*/
var escapeEndingScriptTagRegExp = /<\/script/g;
exports.xs = function escapeScriptHelper(val) {
return (typeof val === 'string') ? val.replace(escapeEndingScriptTagRegExp, '\\u003C/script') : val;
};
/**
* Escapes the '</' sequence in the body of a <style> body to avoid the `<style>` being
* ended prematurely.
*
* For example:
* var color = '</style><script>alert(1)</script>';
*
* <style>#foo { background-color:${color} }</style>
*
* Without escaping the ending '</style>' sequence the opening <style> tag would be
* prematurely ended and a script tag could then be started that could then execute
* arbitrary code.
*/
var escapeEndingStyleTagRegExp = /<\/style/g;
exports.xc = function escapeScriptHelper(val) {
return (typeof val === 'string') ? val.replace(escapeEndingStyleTagRegExp, '\\003C/style') : val;
};
/**
* Internal method to render a single HTML attribute
* @private
*/
exports.a = attrHelper;
/**
* Internal method to render multiple HTML attributes based on the properties of an object
* @private
*/
exports.as = attrsHelper;
/**
* Internal helper method to handle the "style" attribute. The value can either
* be a string or an object with style propertes. For example:
*
* sa('color: red; font-weight: bold') ==> ' style="color: red; font-weight: bold"'
* sa({color: 'red', 'font-weight': 'bold'}) ==> ' style="color: red; font-weight: bold"'
*/
var dashedNames = {};
exports.sa = function(style) {
if (!style) {
return '';
}
var type = typeof style;
if (type === 'string') {
return attrHelper(STYLE_ATTR, style, false);
} else if (type === 'object') {
var styles = '';
for (var name in style) {
var value = style[name];
if (value != null) {
if (typeof value === 'number' && value) {
value += 'px';
}
var nameDashed = dashedNames[name];
if (!nameDashed) {
nameDashed = dashedNames[name] = name.replace(/([A-Z])/g, '-$1').toLowerCase();
}
styles += nameDashed + ':' + value + ';';
}
}
return styles ? ' ' + STYLE_ATTR + '="' + styles +'"' : '';
} else {
return '';
}
};
/**
* Internal helper method to handle the "class" attribute. The value can either
* be a string, an array or an object. For example:
*
* ca('foo bar') ==> ' class="foo bar"'
* ca({foo: true, bar: false, baz: true}) ==> ' class="foo baz"'
* ca(['foo', 'bar']) ==> ' class="foo bar"'
*/
exports.ca = function(classNames) {
if (!classNames) {
return '';
}
if (typeof classNames === 'string') {
return attrHelper(CLASS_ATTR, classNames, false);
} else {
return attrHelper(CLASS_ATTR, classList(classNames), false);
}
};
function classList(arg) {
var len, name, value, str = '';
if (arg) {
if (typeof arg === 'string') {
if (arg) {
str += ' ' + arg;
}
} else if (typeof (len = arg.length) === 'number') {
for (var i=0; i<len; i++) {
value = classList(arg[i]);
if (value) {
str += ' ' + value;
}
}
} else if (typeof arg === 'object') {
for (name in arg) {
value = arg[name];
if (value) {
str += ' ' + name;
}
}
}
}
return (str && str.slice(1)) || null;
}
var commonHelpers = require('../helpers');
extend(exports, commonHelpers);
exports.cl = classList;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
require('../env-init');
var AsyncStream = require('./AsyncStream');
var Template = require('./Template');
/**
* Method is for internal usage only. This method
* is invoked by code in a compiled Marko template and
* it is used to create a new Template instance.
* @private
*/
exports.t = function createTemplate(path) {
return new Template(path);
};
function createOut(globalData, parent, state, buffer) {
return new AsyncStream(globalData, parent, state, buffer);
}
exports.createWriter = function(writer) {
return new AsyncStream(null, writer);
};
exports.Template = Template;
exports.$__createOut = createOut;
exports.AsyncStream = AsyncStream;
exports.enableAsyncStackTrace = AsyncStream.enableAsyncStackTrace;
require('../createOut').$__setCreateOut(createOut);
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index-browser-dynamic.js | 50% | (1 / 2) | 100% | (0 / 0) | 0% | (0 / 1) | 50% | (1 / 2) | |
| index-browser.js | 50% | (1 / 2) | 100% | (0 / 0) | 0% | (0 / 1) | 50% | (1 / 2) | |
| index-default.js | 18.06% | (13 / 72) | 0% | (0 / 39) | 0% | (0 / 7) | 18.06% | (13 / 72) | |
| index.js | 66.67% | (2 / 3) | 50% | (1 / 2) | 0% | (0 / 1) | 66.67% | (2 / 3) |
| 1 2 3 4 5 6 7 8 | 1 | 'use strict'; module.exports = function load(templatePath) { // We make the assumption that the template path is a // fully resolved module path and that the module exists // as a CommonJS module return require(templatePath); }; |
| 1 2 3 4 5 | 1 | 'use strict'; module.exports = function load(templatePath) { throw Error('Not found: ' + templatePath); }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var nodePath = require('path');
var fs = require('fs');
var Module = require('module').Module;
var compilerPath = nodePath.join(__dirname, '../../compiler');
var markoCompiler = require(compilerPath);
var cwd = process.cwd();
var fsOptions = {encoding: 'utf8'};
module.exports = function load(templatePath, templateSrc, options) {
if (typeof templatePath === 'string' && nodePath.extname(templatePath) === '.js') {
// assume compiled template
return require(templatePath);
}
if (arguments.length === 1) {
return doLoad(templatePath);
} else if (arguments.length === 2) {
// see if second argument is templateSrc (a String)
// or options (an Object)
var lastArg = arguments[arguments.length - 1];
if (typeof lastArg === 'string') {
return doLoad(templatePath, templateSrc);
} else {
var finalOptions = templateSrc;
return doLoad(templatePath, null, finalOptions);
}
} else if (arguments.length === 3) {
// assume function called according to function signature
return doLoad(templatePath, templateSrc, options);
} else {
throw new Error('Illegal arguments');
}
};
function loadSource(templatePath, compiledSrc) {
templatePath += '.js';
// Short-circuit loading if the template has already been cached in the Node.js require cache
var cached = require.cache[templatePath];
if (cached) {
return cached.exports;
}
var templateModule = new Module(templatePath, module);
templateModule.paths = Module._nodeModulePaths(nodePath.dirname(templatePath));
templateModule.filename = templatePath;
Module._cache[templatePath] = templateModule;
templateModule._compile(
compiledSrc,
templatePath);
return templateModule.exports;
}
function getCachedTemplate(path) {
var cached = require.cache[path];
return cached && cached.exports.render ? cached.exports : undefined;
}
/**
* This helper function will check the Node.js require cache for the previous
* loaded template and it will also check the disk for the compiled template
* if `options.assumeUpToDate` is true
* @param {String} templatePath The fully resolved path to the template
* @param {Object} options The options for the template
* @return {Template} The loaded template or undefined
*/
function getPreviousTemplate(templatePath, options) {
/*
The require.cache is search in the following order:
1) /path/to/my-template.js
2) /path/to/my-template.marko.js
3) /path/to/my-template.marko
*
If the template is not found in require.cache and `assumeUpToDate` is true
then we will check the disk for the precompiled templates in the following
order:
1) /path/to/my-template.js
2) /path/to/my-template.marko.js
*/
var ext = nodePath.extname(templatePath);
var targetFilePrecompiled = templatePath.slice(0, 0 - ext.length) + '.js';
var targetFileDebug = templatePath + '.js';
// Short-circuit loading if the template has already been cached in the Node.js require cache
var cachedTemplate =
getCachedTemplate(targetFilePrecompiled) ||
getCachedTemplate(targetFileDebug) ||
getCachedTemplate(templatePath);
if (cachedTemplate) {
return cachedTemplate;
}
// Just in case the the path wasn't a fully resolved file system path...
templatePath = nodePath.resolve(cwd, templatePath);
if (options.assumeUpToDate) {
if (fs.existsSync(targetFilePrecompiled)) {
return require(targetFilePrecompiled);
}
if (fs.existsSync(targetFileDebug)) {
return require(targetFileDebug);
}
}
return undefined;
}
function createRenderProxy(template) {
return function(data, out) {
template._(data, out);
};
}
function doLoad(templatePath, templateSrc, options) {
options = Object.assign({}, markoCompiler.defaultOptions, options);
var template;
if (typeof templatePath.render === 'function') {
template = templatePath;
} else {
templatePath = nodePath.resolve(cwd, templatePath);
template = getPreviousTemplate(templatePath, options);
if (!template) {
var writeToDisk = options.writeToDisk;
if (templateSrc == null) {
templateSrc = fs.readFileSync(templatePath, fsOptions);
}
var compiledSrc = markoCompiler.compile(templateSrc, templatePath, options);
if (writeToDisk === true) {
var targetFile = templatePath + '.js';
fs.writeFileSync(targetFile, compiledSrc, fsOptions);
}
template = loadSource(templatePath, compiledSrc);
}
}
if (options.buffer === false) {
var Template = template.constructor;
template = new Template(
template.path,
createRenderProxy(template),
options);
}
return template;
}
|
| 1 2 3 4 5 6 7 8 | 1 1 | Iif (process.env.BUNDLE) { // you cannot load templates dynamically within a bundle // all templates should be pre-compiled as part of the bundle module.exports = function(){}; } else { module.exports = require('./index-default'); } |
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| AsyncVDOMBuilder.js | 13.5% | (22 / 163) | 0% | (0 / 65) | 0% | (0 / 32) | 13.5% | (22 / 163) | |
| VComment.js | 60% | (6 / 10) | 100% | (0 / 0) | 0% | (0 / 3) | 60% | (6 / 10) | |
| VDocumentFragment.js | 56.25% | (9 / 16) | 100% | (0 / 0) | 0% | (0 / 4) | 56.25% | (9 / 16) | |
| VElement.js | 17.42% | (27 / 155) | 0% | (0 / 80) | 5.88% | (1 / 17) | 17.42% | (27 / 155) | |
| VNode.js | 24% | (12 / 50) | 15.63% | (5 / 32) | 28.57% | (2 / 7) | 24% | (12 / 50) | |
| VText.js | 60% | (6 / 10) | 100% | (0 / 0) | 0% | (0 / 3) | 60% | (6 / 10) | |
| helper-styleAttr.js | 10% | (2 / 20) | 0% | (0 / 16) | 0% | (0 / 1) | 10% | (2 / 20) | |
| index.js | 66.67% | (10 / 15) | 100% | (0 / 0) | 0% | (0 / 3) | 66.67% | (10 / 15) | |
| preserve-attrs.js | 30% | (3 / 10) | 0% | (0 / 6) | 0% | (0 / 2) | 30% | (3 / 10) | |
| vdom.js | 30.77% | (24 / 78) | 3.57% | (1 / 28) | 0% | (0 / 6) | 30.77% | (24 / 78) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | var EventEmitter = require('events-light');
var vdom = require('./vdom');
var VElement = vdom.$__VElement;
var VDocumentFragment = vdom.$__VDocumentFragment;
var VComment = vdom.$__VComment;
var VText = vdom.$__VText;
var virtualizeHTML = vdom.$__virtualizeHTML;
var RenderResult = require('../RenderResult');
var defaultDocument = vdom.$__defaultDocument;
var FLAG_FINISHED = 1;
var FLAG_LAST_FIRED = 2;
var EVENT_UPDATE = 'update';
var EVENT_FINISH = 'finish';
function State(tree) {
this.$__remaining = 1;
this.$__events = new EventEmitter();
this.$__tree = tree;
this.$__last = null;
this.$__lastCount = 0;
this.$__flags = 0;
}
function AsyncVDOMBuilder(globalData, parentNode, state) {
if (!parentNode) {
parentNode = new VDocumentFragment();
}
if (state) {
state.$__remaining++;
} else {
state = new State(parentNode);
}
this.data = {};
this.$__state = state;
this.$__parent = parentNode;
this.global = globalData || {};
this.$__stack = [parentNode];
this.$__sync = false;
this.$__vnode = undefined;
this.$c = null; // Component args
}
var proto = AsyncVDOMBuilder.prototype = {
$__isOut: true,
$__document: defaultDocument,
element: function(tagName, attrs, childCount, flags, props) {
var element = new VElement(tagName, attrs, childCount, flags, props);
var parent = this.$__parent;
if (parent !== undefined) {
parent.$__appendChild(element);
}
return childCount === 0 ? this : element;
},
n: function(node) {
// NOTE: We do a shallow clone since we assume the node is being reused
// and a node can only have one parent node.
return this.node(node.$__cloneNode());
},
node: function(node) {
var parent = this.$__parent;
if (parent !== undefined) {
parent.$__appendChild(node);
}
return this;
},
text: function(text) {
var type = typeof text;
if (type != 'string') {
if (text == null) {
return;
} else if (type === 'object') {
if (text.toHTML) {
return this.h(text.toHTML());
}
}
text = text.toString();
}
var parent = this.$__parent;
if (parent !== undefined) {
var lastChild = parent.lastChild;
if (lastChild && lastChild.$__Text) {
lastChild.nodeValue += text;
} else {
parent.$__appendChild(new VText(text));
}
}
return this;
},
comment: function(comment) {
return this.node(new VComment(comment));
},
html: function(html) {
if (html != null) {
var vdomNode = virtualizeHTML(html, this.$__document);
this.node(vdomNode);
}
return this;
},
beginElement: function(name, attrs, childCount, flags, constId) {
var element = new VElement(name, attrs, childCount, flags, constId);
var parent = this.$__parent;
if (parent !== undefined) {
parent.$__appendChild(element);
this.$__stack.push(element);
this.$__parent = element;
}
return this;
},
endElement: function() {
var stack = this.$__stack;
stack.pop();
this.$__parent = stack[stack.length-1];
},
end: function() {
var state = this.$__state;
this.$__parent = undefined;
var remaining = --state.$__remaining;
if (!(state.$__flags & FLAG_LAST_FIRED) && (remaining - state.$__lastCount === 0)) {
state.$__flags |= FLAG_LAST_FIRED;
state.$__lastCount = 0;
state.$__events.emit('last');
}
if (remaining === 0) {
state.$__flags |= FLAG_FINISHED;
state.$__events.emit(EVENT_FINISH, this.$__getResult());
}
return this;
},
error: function(e) {
try {
this.emit('error', e);
} finally {
// If there is no listener for the error event then it will
// throw a new Error here. In order to ensure that the async fragment
// is still properly ended we need to put the end() in a `finally`
// block
this.end();
}
return this;
},
beginAsync: function(options) {
if (this.$__sync) {
throw Error('Not allowed');
}
var state = this.$__state;
if (options) {
if (options.last) {
state.$__lastCount++;
}
}
var documentFragment = this.$__parent.$__appendDocumentFragment();
var asyncOut = new AsyncVDOMBuilder(this.global, documentFragment, state);
state.$__events.emit('beginAsync', {
out: asyncOut,
parentOut: this
});
return asyncOut;
},
createOut: function(callback) {
return new AsyncVDOMBuilder(this.global);
},
flush: function() {
var events = this.$__state.$__events;
if (events.listenerCount(EVENT_UPDATE)) {
events.emit(EVENT_UPDATE, new RenderResult(this));
}
},
$__getOutput: function() {
return this.$__state.$__tree;
},
$__getResult: function() {
return this.$__result || (this.$__result = new RenderResult(this));
},
on: function(event, callback) {
var state = this.$__state;
if (event === EVENT_FINISH && (state.$__flags & FLAG_FINISHED)) {
callback(this.$__getResult());
} else {
state.$__events.on(event, callback);
}
return this;
},
once: function(event, callback) {
var state = this.$__state;
if (event === EVENT_FINISH && (state.$__flags & FLAG_FINISHED)) {
callback(this.$__getResult());
return this;
}
state.$__events.once(event, callback);
return this;
},
emit: function(type, arg) {
var events = this.$__state.$__events;
switch(arguments.length) {
case 1:
events.emit(type);
break;
case 2:
events.emit(type, arg);
break;
default:
events.emit.apply(events, arguments);
break;
}
return this;
},
removeListener: function() {
var events = this.$__state.$__events;
events.removeListener.apply(events, arguments);
return this;
},
sync: function() {
this.$__sync = true;
},
isSync: function() {
return this.$__sync;
},
onLast: function(callback) {
var state = this.$__state;
var lastArray = state.$__last;
if (!lastArray) {
lastArray = state.$__last = [];
var i = 0;
var next = function() {
if (i === lastArray.length) {
return;
}
var _next = lastArray[i++];
_next(next);
};
this.once('last', function() {
next();
});
}
lastArray.push(callback);
return this;
},
$__getNode: function(doc) {
var node = this.$__vnode;
if (!node) {
var vdomTree = this.$__getOutput();
node = this.$__vnode = vdomTree.actualize(doc || this.$__document);
}
return node;
},
toString: function() {
return this.$__getNode().outerHTML;
},
then: function(fn, fnErr) {
var out = this;
var promise = new Promise(function(resolve, reject) {
out.on('error', reject)
.on(EVENT_FINISH, function(result) {
resolve(result);
});
});
return Promise.resolve(promise).then(fn, fnErr);
},
catch: function(fnErr) {
return this.then(undefined, fnErr);
},
isVDOM: true
};
proto.e = proto.element;
proto.be = proto.beginElement;
proto.ee = proto.endElement;
proto.t = proto.text;
proto.h = proto.w = proto.write = proto.html;
module.exports = AsyncVDOMBuilder;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 1 1 1 1 1 1 | var VNode = require('./VNode');
var inherit = require('raptor-util/inherit');
function VComment(value) {
this.$__VNode(-1 /* no children */);
this.nodeValue = value;
}
VComment.prototype = {
$__nodeType: 8,
$__actualize: function(doc) {
return doc.createComment(this.nodeValue);
},
$__cloneNode: function() {
return new VComment(this.nodeValue);
}
};
inherit(VComment, VNode);
module.exports = VComment;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 1 1 1 1 1 1 1 1 1 | var VNode = require('./VNode');
var inherit = require('raptor-util/inherit');
var extend = require('raptor-util/extend');
function VDocumentFragmentClone(other) {
extend(this, other);
this.$__parentNode = null;
this.$__nextSibling = null;
}
function VDocumentFragment(documentFragment) {
this.$__VNode(null /* childCount */);
this.namespaceURI = null;
}
VDocumentFragment.prototype = {
$__nodeType: 11,
$__DocumentFragment: true,
$__cloneNode: function() {
return new VDocumentFragmentClone(this);
},
$__actualize: function(doc) {
return doc.createDocumentFragment();
}
};
inherit(VDocumentFragment, VNode);
VDocumentFragmentClone.prototype = VDocumentFragment.prototype;
module.exports = VDocumentFragment;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 1 1 1 1 1 | var VNode = require('./VNode');
var inherit = require('raptor-util/inherit');
var NS_XLINK = 'http://www.w3.org/1999/xlink';
var ATTR_XLINK_HREF = 'xlink:href';
var toString = String;
var FLAG_IS_SVG = 1;
var FLAG_IS_TEXTAREA = 2;
var FLAG_SIMPLE_ATTRS = 4;
var defineProperty = Object.defineProperty;
var ATTR_HREF = 'href';
var EMPTY_OBJECT = Object.freeze({});
function convertAttrValue(type, value) {
if (value === true) {
return '';
} else if (type == 'object') {
return JSON.stringify(value);
} else {
return toString(value);
}
}
function setAttribute(el, namespaceURI, name, value) {
if (namespaceURI === null) {
el.setAttribute(name, value);
} else {
el.setAttributeNS(namespaceURI, name, value);
}
}
function removeAttribute(el, namespaceURI, name) {
if (namespaceURI === null) {
el.removeAttribute(name);
} else {
el.removeAttributeNS(namespaceURI, name);
}
}
function VElementClone(other) {
this.$__firstChild = other.$__firstChild;
this.$__parentNode = null;
this.$__nextSibling = null;
this.$__attributes = other.$__attributes;
this.$__properties = other.$__properties;
this.$__namespaceURI = other.$__namespaceURI;
this.$__nodeName = other.$__nodeName;
this.$__flags = other.$__flags;
this.$__value = other.$__value;
this.$__constId = other.$__constId;
}
function VElement(tagName, attrs, childCount, flags, props) {
this.$__VNode(childCount);
var constId;
if (props) {
constId = props.c;
}
var namespaceURI;
if ((this.$__flags = flags || 0)) {
if (flags & FLAG_IS_SVG) {
namespaceURI = 'http://www.w3.org/2000/svg';
}
}
this.$__attributes = attrs || EMPTY_OBJECT;
this.$__properties = props || EMPTY_OBJECT;
this.$__namespaceURI = namespaceURI;
this.$__nodeName = tagName;
this.$__value = null;
this.$__constId = constId;
}
VElement.prototype = {
$__VElement: true,
$__nodeType: 1,
$__cloneNode: function() {
return new VElementClone(this);
},
/**
* Shorthand method for creating and appending an HTML element
*
* @param {String} tagName The tag name (e.g. "div")
* @param {int|null} attrCount The number of attributes (or `null` if not known)
* @param {int|null} childCount The number of child nodes (or `null` if not known)
*/
e: function(tagName, attrs, childCount, flags, props) {
var child = this.$__appendChild(new VElement(tagName, attrs, childCount, flags, props));
if (childCount === 0) {
return this.$__finishChild();
} else {
return child;
}
},
/**
* Shorthand method for creating and appending a static node. The provided node is automatically cloned
* using a shallow clone since it will be mutated as a result of setting `nextSibling` and `parentNode`.
*
* @param {String} value The value for the new Comment node
*/
n: function(node) {
this.$__appendChild(node.$__cloneNode());
return this.$__finishChild();
},
$__actualize: function(doc) {
var namespaceURI = this.$__namespaceURI;
var tagName = this.$__nodeName;
var attributes = this.$__attributes;
var flags = this.$__flags;
var el = namespaceURI !== undefined ?
doc.createElementNS(namespaceURI, tagName) :
doc.createElement(tagName);
for (var attrName in attributes) {
var attrValue = attributes[attrName];
if (attrValue !== false && attrValue != null) {
var type = typeof attrValue;
if (type !== 'string') {
// Special attributes aren't copied to the real DOM. They are only
// kept in the virtual attributes map
attrValue = convertAttrValue(type, attrValue);
}
if (attrName == ATTR_XLINK_HREF) {
setAttribute(el, NS_XLINK, ATTR_HREF, attrValue);
} else {
el.setAttribute(attrName, attrValue);
}
}
}
if (flags & FLAG_IS_TEXTAREA) {
el.value = this.$__value;
}
el._vattrs = attributes;
el._vprops = this.$__properties;
el._vflags = flags;
return el;
},
$__hasAttribute: function(name) {
// We don't care about the namespaces since the there
// is no chance that attributes with the same name will have
// different namespaces
var value = this.$__attributes[name];
return value != null && value !== false;
},
};
inherit(VElement, VNode);
var proto = VElementClone.prototype = VElement.prototype;
['checked', 'selected', 'disabled'].forEach(function(name) {
defineProperty(proto, name, {
get: function () {
var value = this.$__attributes[name];
return value !== false && value != null;
}
});
});
defineProperty(proto, 'id', {
get: function () {
return this.$__attributes.id;
}
});
defineProperty(proto, 'value', {
get: function () {
var value = this.$__value;
if (value == null) {
value = this.$__attributes.value;
}
return value != null ? toString(value) : '';
}
});
defineProperty(proto, '$__isTextArea', {
get: function () {
return this.$__flags & FLAG_IS_TEXTAREA;
}
});
VElement.$__removePreservedAttributes = function(attrs) {
// By default this static method is a no-op, but if there are any
// compiled components that have "no-update" attributes then
// `preserve-attrs.js` will be imported and this method will be replaced
// with a method that actually does something
return attrs;
};
VElement.$__morphAttrs = function(fromEl, toEl) {
var removePreservedAttributes = VElement.$__removePreservedAttributes;
var attrs = toEl.$__attributes;
var props = fromEl._vprops = toEl.$__properties;
var attrName;
var i;
// We use expando properties to associate the previous HTML
// attributes provided as part of the VDOM node with the
// real VElement DOM node. When diffing attributes,
// we only use our internal representation of the attributes.
// When diffing for the first time it's possible that the
// real VElement node will not have the expando property
// so we build the attribute map from the expando property
var oldAttrs = fromEl._vattrs;
if (oldAttrs) {
if (oldAttrs == attrs) {
// For constant attributes the same object will be provided
// every render and we can use that to our advantage to
// not waste time diffing a constant, immutable attribute
// map.
return;
} else {
oldAttrs = removePreservedAttributes(oldAttrs, props, true);
}
} else {
// We need to build the attribute map from the real attributes
oldAttrs = {};
var oldAttributesList = fromEl.attributes;
for (i = oldAttributesList.length - 1; i >= 0; --i) {
var attr = oldAttributesList[i];
if (attr.specified !== false) {
attrName = attr.name;
if (attrName !== 'data-marko') {
var attrNamespaceURI = attr.namespaceURI;
if (attrNamespaceURI === NS_XLINK) {
oldAttrs[ATTR_XLINK_HREF] = attr.value;
} else {
oldAttrs[attrName] = attr.value;
}
}
}
}
// We don't want preserved attributes to show up in either the old
// or new attribute map.
removePreservedAttributes(oldAttrs, props, false);
}
fromEl._vattrs = attrs;
var attrValue;
var flags = toEl.$__flags;
var oldFlags;
if (flags & FLAG_SIMPLE_ATTRS && ((oldFlags = fromEl._vflags) & FLAG_SIMPLE_ATTRS)) {
if (oldAttrs['class'] !== (attrValue = attrs['class'])) {
fromEl.className = attrValue;
}
if (oldAttrs.id !== (attrValue = attrs.id)) {
fromEl.id = attrValue;
}
if (oldAttrs.style !== (attrValue = attrs.style)) {
fromEl.style.cssText = attrValue;
}
return;
}
// In some cases we only want to set an attribute value for the first
// render or we don't want certain attributes to be touched. To support
// that use case we delete out all of the preserved attributes
// so it's as if they never existed.
attrs = removePreservedAttributes(attrs, props, true);
var namespaceURI;
// Loop over all of the attributes in the attribute map and compare
// them to the value in the old map. However, if the value is
// null/undefined/false then we want to remove the attribute
for (attrName in attrs) {
attrValue = attrs[attrName];
namespaceURI = null;
if (attrName === ATTR_XLINK_HREF) {
namespaceURI = NS_XLINK;
attrName = ATTR_HREF;
}
if (attrValue == null || attrValue === false) {
removeAttribute(fromEl, namespaceURI, attrName);
} else if (oldAttrs[attrName] !== attrValue) {
var type = typeof attrValue;
if (type !== 'string') {
attrValue = convertAttrValue(type, attrValue);
}
setAttribute(fromEl, namespaceURI, attrName, attrValue);
}
}
// If there are any old attributes that are not in the new set of attributes
// then we need to remove those attributes from the target node
//
// NOTE: We can skip this if the the element is keyed because if the element
// is keyed then we know we already processed all of the attributes for
// both the target and original element since target VElement nodes will
// have all attributes declared. However, we can only skip if the node
// was not a virtualized node (i.e., a node that was not rendered by a
// Marko template, but rather a node that was created from an HTML
// string or a real DOM node).
if (!attrs.id || props.$__virtualized === true) {
for (attrName in oldAttrs) {
if (!(attrName in attrs)) {
if (attrName === ATTR_XLINK_HREF) {
fromEl.removeAttributeNS(ATTR_XLINK_HREF, ATTR_HREF);
} else {
fromEl.removeAttribute(attrName);
}
}
}
}
};
module.exports = VElement;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | 1 1 1 2 2 2 2 2 2 2 2 1 | /* jshint newcap:false */
var specialElHandlers = require('../../morphdom/specialElHandlers');
function VNode() {}
VNode.prototype = {
$__VNode: function(finalChildCount) {
this.$__finalChildCount = finalChildCount;
this.$__childCount = 0;
this.$__firstChild = null;
this.$__lastChild = null;
this.$__parentNode = null;
this.$__nextSibling = null;
},
get firstChild() {
var firstChild = this.$__firstChild;
Iif (firstChild && firstChild.$__DocumentFragment) {
var nestedFirstChild = firstChild.firstChild;
// The first child is a DocumentFragment node.
// If the DocumentFragment node has a first child then we will return that.
// Otherwise, the DocumentFragment node is not *really* the first child and
// we need to skip to its next sibling
return nestedFirstChild || firstChild.nextSibling;
}
return firstChild;
},
get nextSibling() {
var nextSibling = this.$__nextSibling;
Iif (nextSibling) {
if (nextSibling.$__DocumentFragment) {
var firstChild = nextSibling.firstChild;
return firstChild || nextSibling.nextSibling;
}
} else {
var parentNode = this.$__parentNode;
Iif (parentNode && parentNode.$__DocumentFragment) {
return parentNode.nextSibling;
}
}
return nextSibling;
},
$__appendChild: function(child) {
this.$__childCount++;
if (this.$__isTextArea) {
if (child.$__Text) {
var childValue = child.nodeValue;
this.$__value = (this.$__value || '') + childValue;
} else {
throw TypeError();
}
} else {
var lastChild = this.$__lastChild;
child.$__parentNode = this;
if (lastChild) {
lastChild.$__nextSibling = child;
} else {
this.$__firstChild = child;
}
this.$__lastChild = child;
}
return child;
},
$__finishChild: function finishChild() {
if (this.$__childCount == this.$__finalChildCount && this.$__parentNode) {
return this.$__parentNode.$__finishChild();
} else {
return this;
}
},
actualize: function(doc) {
var actualNode = this.$__actualize(doc);
var curChild = this.firstChild;
while(curChild) {
actualNode.appendChild(curChild.actualize(doc));
curChild = curChild.nextSibling;
}
if (this.$__nodeType === 1) {
var elHandler = specialElHandlers[this.$__nodeName];
if (elHandler !== undefined) {
elHandler(actualNode, this);
}
}
return actualNode;
}
// ,toJSON: function() {
// var clone = Object.assign({
// nodeType: this.nodeType
// }, this);
//
// for (var k in clone) {
// if (k.startsWith('_')) {
// delete clone[k];
// }
// }
// delete clone._nextSibling;
// delete clone._lastChild;
// delete clone.parentNode;
// return clone;
// }
};
module.exports = VNode;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 1 1 1 1 1 1 | var VNode = require('./VNode');
var inherit = require('raptor-util/inherit');
function VText(value) {
this.$__VNode(-1 /* no children */);
this.nodeValue = value;
}
VText.prototype = {
$__Text: true,
$__nodeType: 3,
$__actualize: function(doc) {
return doc.createTextNode(this.nodeValue);
},
$__cloneNode: function() {
return new VText(this.nodeValue);
}
};
inherit(VText, VNode);
module.exports = VText;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 1 1 | var dashedNames = {};
/**
* Helper for generating the string for a style attribute
* @param {[type]} style [description]
* @return {[type]} [description]
*/
module.exports = function(style) {
if (!style) {
return null;
}
var type = typeof style;
if (type === 'string') {
return style;
} else if (type === 'object') {
var styles = '';
for (var name in style) {
var value = style[name];
if (value != null) {
if (typeof value === 'number' && value) {
value += 'px';
}
var nameDashed = dashedNames[name];
if (!nameDashed) {
nameDashed = dashedNames[name] = name.replace(/([A-Z])/g, '-$1').toLowerCase();
}
styles += nameDashed + ':' + value + ';';
}
}
return styles || null;
} else {
return null;
}
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 1 1 1 1 1 1 1 1 1 1 | 'use strict';
// helpers provide a core set of various utility methods
// that are available in every template
var AsyncVDOMBuilder = require('./AsyncVDOMBuilder');
var makeRenderable = require('../renderable');
/**
* Method is for internal usage only. This method
* is invoked by code in a compiled Marko template and
* it is used to create a new Template instance.
* @private
*/
exports.t = function createTemplate(path) {
return new Template(path);
};
function Template(path, func) {
this.path = path;
this._ = func;
this.meta = undefined;
}
function createOut(globalData, parent, state) {
return new AsyncVDOMBuilder(globalData, parent, state);
}
var Template_prototype = Template.prototype = {
createOut: createOut
};
makeRenderable(Template_prototype);
exports.Template = Template;
exports.$__createOut = createOut;
require('../createOut').$__setCreateOut(createOut);
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 1 1 1 | var extend = require('raptor-util/extend');
function removePreservedAttributes(attrs, props, clone) {
var preservedAttrs = props && props.noupdate;
if (preservedAttrs) {
if (clone) {
attrs = extend({}, attrs);
}
preservedAttrs.forEach(function(preservedAttrName) {
delete attrs[preservedAttrName];
});
}
return attrs;
}
require('./VElement').$__removePreservedAttributes = removePreservedAttributes;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | var VNode = require('./VNode');
var VComment = require('./VComment');
var VDocumentFragment = require('./VDocumentFragment');
var VElement = require('./VElement');
var VText = require('./VText');
var FLAG_IS_TEXTAREA = 2;
var defaultDocument = typeof document != 'undefined' && document;
var specialHtmlRegexp = /[&<]/;
var xmlnsRegExp = /^xmlns(:|$)/;
var virtualizedProps = { $__virtualized: true };
function virtualizeChildNodes(node, vdomParent) {
var curChild = node.firstChild;
while(curChild) {
vdomParent.$__appendChild(virtualize(curChild));
curChild = curChild.nextSibling;
}
}
function virtualize(node) {
switch(node.nodeType) {
case 1:
var attributes = node.attributes;
var attrCount = attributes.length;
var attrs;
if (attrCount) {
attrs = {};
for (var i=0; i<attrCount; i++) {
var attr = attributes[i];
var attrName = attr.name;
if (!xmlnsRegExp.test(attrName)) {
attrs[attrName] = attr.value;
}
}
}
var flags = 0;
var tagName = node.nodeName;
if (tagName === 'TEXTAREA') {
flags |= FLAG_IS_TEXTAREA;
}
var vdomEl = new VElement(tagName, attrs, null, flags, virtualizedProps);
if (node.namespaceURI !== 'http://www.w3.org/1999/xhtml') {
vdomEl.$__namespaceURI = node.namespaceURI;
}
if (vdomEl.$__isTextArea) {
vdomEl.$__value = node.value;
} else {
virtualizeChildNodes(node, vdomEl);
}
return vdomEl;
case 3:
return new VText(node.nodeValue);
case 8:
return new VComment(node.nodeValue);
case 11:
var vdomDocFragment = new VDocumentFragment();
virtualizeChildNodes(node, vdomDocFragment);
return vdomDocFragment;
}
}
function virtualizeHTML(html, doc) {
if (!specialHtmlRegexp.test(html)) {
return new VText(html);
}
var container = doc.createElement('body');
container.innerHTML = html;
var vdomFragment = new VDocumentFragment();
var curChild = container.firstChild;
while(curChild) {
vdomFragment.$__appendChild(virtualize(curChild));
curChild = curChild.nextSibling;
}
return vdomFragment;
}
var Node_prototype = VNode.prototype;
/**
* Shorthand method for creating and appending a Text node with a given value
* @param {String} value The text value for the new Text node
*/
Node_prototype.t = function(value) {
var type = typeof value;
var vdomNode;
if (type !== 'string') {
if (value == null) {
value = '';
} else if (type === 'object') {
if (value.toHTML) {
vdomNode = virtualizeHTML(value.toHTML(), document);
}
}
}
this.$__appendChild(vdomNode || new VText(value.toString()));
return this.$__finishChild();
};
/**
* Shorthand method for creating and appending a Comment node with a given value
* @param {String} value The value for the new Comment node
*/
Node_prototype.c = function(value) {
this.$__appendChild(new VComment(value));
return this.$__finishChild();
};
Node_prototype.$__appendDocumentFragment = function() {
return this.$__appendChild(new VDocumentFragment());
};
exports.$__VComment = VComment;
exports.$__VDocumentFragment = VDocumentFragment;
exports.$__VElement = VElement;
exports.$__VText = VText;
exports.$__virtualize = virtualize;
exports.$__virtualizeHTML = virtualizeHTML;
exports.$__defaultDocument = defaultDocument;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| async-fragment-to-await-transformer.js | 10.53% | (2 / 19) | 0% | (0 / 4) | 0% | (0 / 1) | 10.53% | (2 / 19) | |
| await-nested-tag-transformer.js | 6.67% | (1 / 15) | 0% | (0 / 8) | 0% | (0 / 1) | 6.67% | (1 / 15) | |
| await-reorderer-tag.js | 7.32% | (3 / 41) | 0% | (0 / 21) | 0% | (0 / 5) | 7.32% | (3 / 41) | |
| await-tag-transformer.js | 3.92% | (2 / 51) | 0% | (0 / 24) | 0% | (0 / 1) | 3.92% | (2 / 51) | |
| await-tag.js | 8.55% | (10 / 117) | 0% | (0 / 79) | 0% | (0 / 12) | 8.62% | (10 / 116) | |
| client-reorder-browser.js | 100% | (1 / 1) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (1 / 1) | |
| client-reorder-runtime.js | 4.76% | (1 / 21) | 0% | (0 / 8) | 0% | (0 / 1) | 4.76% | (1 / 21) | |
| client-reorder.js | 50% | (4 / 8) | 0% | (0 / 2) | 0% | (0 / 1) | 50% | (4 / 8) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | 1 1 | 'use strict';
var newTags = {
'async-fragment':'await',
'async-fragments':'await-reorderer',
'async-fragment-placeholder':'await-placeholder',
'async-fragment-timeout':'await-timeout',
'async-fragment-error':'await-error'
};
module.exports = function transform(oldNode, context) {
var oldTag = oldNode.tagName;
var newTag = newTags[oldTag];
var provider;
var varName;
var argument;
context.deprecate('The <'+oldTag+'> tag is deprecated. Please use <'+newTag+'> instead.');
if(oldTag == 'async-fragment'/* new: <await> */) {
// need to convert data-provider and var attributes
// to an argument: <await(var from dataProvider)>
varName = oldNode.getAttributeValue('var').value;
provider = oldNode.getAttributeValue('data-provider').toString();
argument = varName + ' from ' + provider;
// now remove the attributes
oldNode.removeAttribute('var');
oldNode.removeAttribute('data-provider');
}
if(oldTag == 'async-fragments'/* new: <await-reorderer> */) {
// all this tag ever did was handling of client reordering
// we'll remove the attribute as that's all this new tag does
oldNode.removeAttribute('client-reorder');
}
var newNode = context.createNodeForEl(
newTag,
oldNode.getAttributes(),
argument
);
oldNode.replaceWith(newNode);
oldNode.moveChildrenTo(newNode);
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 1 | 'use strict'; module.exports = function transform(el, context) { var parentNode = el.parentNode; if (parentNode.tagName !== 'await') { context.addError('The <' + el.tagName + '> should be nested within an <await> tag.'); return; } var targetProp; if (el.tagName === 'await-error') { targetProp = 'renderError'; } else if (el.tagName === 'await-timeout') { targetProp = 'renderTimeout'; } else if (el.tagName === 'await-placeholder') { targetProp = 'renderPlaceholder'; } var builder = context.builder; parentNode.setAttributeValue(targetProp, builder.renderBodyFunction(el.body)); el.detach(); }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | 1 1 1 | 'use strict';
const clientReorder = require('./client-reorder');
module.exports = function(input, out) {
// We cannot call beginSync() when using renderSync(). In this case we will
// ignore the await-reorderer tag.
if (out.isSync()) {
return;
}
var global = out.global;
out.flush();
// We have already invoked an <await-reorderer. We do not need to do this
// work again.
if (global.__awaitReordererInvoked) {
return;
}
global.__awaitReordererInvoked = true;
var asyncOut = out.beginAsync({ last: true, timeout: -1, name: 'await-reorderer' });
out.onLast(function(next) {
var awaitContext = global.__awaitContext;
var remaining;
// Validate that we have remaining <await> instances that need handled
if (!awaitContext || !awaitContext.instances || !(remaining = awaitContext.instances.length)) {
asyncOut.end();
next();
return;
}
var done = false;
function handleAwait(awaitInfo) {
awaitInfo.asyncValue.done(function(err, html) {
if (done) {
return;
}
if (err) {
done = true;
return asyncOut.error(err);
}
if (!global._afRuntime) {
asyncOut.write(clientReorder.getCode());
global._afRuntime = true;
}
asyncOut.write('<div id="af' + awaitInfo.id + '" style="display:none">' +
html +
'</div>' +
'<script type="text/javascript">$af(' +
(typeof awaitInfo.id === 'number' ? awaitInfo.id : '"' + awaitInfo.id + '"') +
(awaitInfo.after ? (',"' + awaitInfo.after + '"') : '' ) +
')</script>');
awaitInfo.out.writer = asyncOut.writer;
out.emit('await:finish', awaitInfo);
out.flush();
if (--remaining === 0) {
done = true;
asyncOut.end();
next();
}
});
}
awaitContext.instances.forEach(handleAwait);
out.on('await:clientReorder', function(awaitInfo) {
remaining++;
handleAwait(awaitInfo);
});
// Now that we have a listener attached, we want to receive any additional
// out-of-sync instances via an event
delete awaitContext.instances;
});
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | 1 1 | 'use strict';
var isObjectEmpty = require('raptor-util/isObjectEmpty');
module.exports = function transform(el, context) {
if(!el.argument) {
context.addError('Invalid <await> tag. Argument is missing. Example: <await(user from data.userProvider)>');
return;
}
var match = /^([$A-Z_][0-9A-Z_$]*) from (.*)$/i.exec(el.argument);
if(!match) {
context.addError('Invalid <await> tag. Argument is malformed. Example: <await(user from data.userProvider)>');
return;
}
var varName = match[1];
var dataProviderAttr = match[2];
if (!context.util.isValidJavaScriptIdentifier(varName)) {
context.addError('Invalid <await> tag. Argument\'s variable name should be a valid JavaScript identifier. Example: user, as in <await(user from data.userProvider)>');
return;
}
var builder = context.builder;
el.setAttributeValue('_var', builder.literal(varName));
el.setAttributeValue('_dataProvider', builder.parseExpression(dataProviderAttr));
el.argument = null;
////////////////////
var attrs = el.getAttributes().concat([]);
var arg = {};
attrs.forEach((attr) => {
var attrName = attr.name;
if (attrName.startsWith('arg-')) {
let argName = attrName.substring('arg-'.length);
arg[argName] = attr.value;
el.removeAttribute(attrName);
}
});
var name = el.getAttributeValue('name');
if (name == null) {
el.setAttributeValue('_name', builder.literal(dataProviderAttr));
}
if (el.hasAttribute('arg')) {
if (isObjectEmpty(arg)) {
arg = el.getAttributeValue('arg');
} else {
let mergeVar = context.helper('merge');
arg = builder.functionCall(mergeVar, [
builder.literal(arg), // Input props from the attributes take precedence
el.getAttributeValue('arg')
]);
}
} else {
if (isObjectEmpty(arg)) {
arg = null;
} else {
arg = builder.literal(arg);
}
}
if (arg) {
el.setAttributeValue('arg', arg);
}
var timeoutMessage = el.getAttributeValue('timeout-message');
if (timeoutMessage) {
el.removeAttribute('timeout-message');
el.setAttributeValue('renderTimeout', builder.renderBodyFunction([
builder.text(timeoutMessage)
]));
}
var errorMessage = el.getAttributeValue('error-message');
if (errorMessage) {
el.removeAttribute('error-message');
el.setAttributeValue('renderError', builder.renderBodyFunction([
builder.text(errorMessage)
]));
}
var placeholder = el.getAttributeValue('placeholder');
if (placeholder) {
el.removeAttribute('placeholder');
el.setAttributeValue('renderPlaceholder', builder.renderBodyFunction([
builder.text(placeholder)
]));
}
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var logger = require('raptor-logging').logger(module);
var AsyncValue = require('raptor-async/AsyncValue');
var isClientReorderSupported = require('./client-reorder').isSupported;
var nextTick = require('../../runtime/nextTick');
function isPromise(o) {
return o && typeof o.then === 'function';
}
function safeRenderBody(renderBody, targetOut, data) {
try {
renderBody(targetOut, data);
} catch(err) {
return err;
}
}
function promiseToCallback(promise, callback, thisObj) {
if (callback) {
var finalPromise = promise
.then(function(data) {
nextTick(callback.bind(this, null, data));
})
.then(null, function(err) {
nextTick(callback.bind(this, err));
});
if (finalPromise.done) {
finalPromise.done();
}
}
return promise;
}
function requestData(provider, args, callback, thisObj) {
if (isPromise(provider)) {
// promises don't support a scope so we can ignore thisObj
promiseToCallback(provider, callback);
return;
}
if (typeof provider === 'function') {
var data = (provider.length === 1) ?
// one argument so only provide callback to function call
provider.call(thisObj, callback) :
// two arguments so provide args and callback to function call
provider.call(thisObj, args, callback);
if (data !== undefined) {
if (isPromise(data)) {
promiseToCallback(data, callback);
}
else {
callback(null, data);
}
}
} else {
// Assume the provider is a data object...
callback(null, provider);
}
}
module.exports = function awaitTag(input, out) {
var dataProvider = input._dataProvider;
var arg = input.arg || {};
arg.out = out;
var clientReorder = isClientReorderSupported && input.clientReorder === true && !out.isVDOM;
var asyncOut;
var timeoutId = null;
var name = input.name || input._name;
var scope = input.scope || this;
var method = input.method;
if (method) {
dataProvider = dataProvider[method].bind(dataProvider);
}
var awaitInfo = {
name: name,
clientReorder: clientReorder,
dataProvider: dataProvider
};
var beforeRenderEmitted = false;
out.emit('await:begin', awaitInfo);
function renderBody(err, data, renderTimeout) {
if (awaitInfo.finished) return;
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = null;
}
var targetOut = awaitInfo.out = asyncOut || out;
if (!beforeRenderEmitted) {
beforeRenderEmitted = true;
out.emit('await:beforeRender', awaitInfo);
}
if (err) {
if (input.renderError) {
console.error('Await (' + name + ') failed. Error:', (err.stack || err));
input.renderError(targetOut);
} else {
targetOut.error(err);
}
} else if (renderTimeout) {
renderTimeout(targetOut);
} else {
var renderBodyFunc = input.renderBody;
if (renderBodyFunc) {
var renderBodyErr = safeRenderBody(renderBodyFunc, targetOut, data);
if (renderBodyErr) {
return renderBody(renderBodyErr);
}
}
}
awaitInfo.finished = true;
if (!clientReorder) {
out.emit('await:finish', awaitInfo);
}
if (asyncOut) {
asyncOut.end();
// Only flush if we rendered asynchronously and we aren't using
// client-reordering
if (!clientReorder) {
out.flush();
}
}
}
requestData(dataProvider, arg, renderBody, scope);
if (!awaitInfo.finished) {
var timeout = input.timeout;
var renderTimeout = input.renderTimeout;
var renderPlaceholder = input.renderPlaceholder;
if (timeout == null) {
timeout = 10000;
} else if (timeout <= 0) {
timeout = null;
}
if (timeout != null) {
timeoutId = setTimeout(function() {
var message = 'Await (' + name + ') timed out after ' + timeout + 'ms';
awaitInfo.timedout = true;
if (renderTimeout) {
logger.error(message);
renderBody(null, null, renderTimeout);
} else {
renderBody(new Error(message));
}
}, timeout);
}
if (clientReorder) {
var awaitContext = out.global.__awaitContext || (awaitContext = out.global.__awaitContext = {
instances: [],
nextId: 0
});
var id = awaitInfo.id = input.name || (awaitContext.nextId++);
var placeholderIdAttrValue = 'afph' + id;
if (renderPlaceholder) {
out.write('<span id="' + placeholderIdAttrValue + '">');
renderPlaceholder(out);
out.write('</span>');
} else {
out.write('<noscript id="' + placeholderIdAttrValue + '"></noscript>');
}
var asyncValue = awaitInfo.asyncValue = new AsyncValue();
// If `client-reorder` is enabled then we asynchronously render the await instance to a new
// AsyncWriter instance so that we can Write to a temporary in-memory buffer.
asyncOut = awaitInfo.out = out.createOut();
awaitInfo.after = input.showAfter;
var oldEmit = asyncOut.emit;
// Since we are rendering the await instance to a new and separate out,
// we want to proxy any child events to the main AsyncWriter in case anyone is interested
// in those events. This is also needed for the following events to be handled correctly:
//
// - await:begin
// - await:beforeRender
// - await:finish
//
asyncOut.emit = function(event) {
if (event !== 'finish' && event !== 'error') {
// We don't want to proxy the finish and error events since those are
// very specific to the AsyncWriter associated with the await instance
out.emit.apply(out, arguments);
}
oldEmit.apply(asyncOut, arguments);
};
asyncOut
.on('finish', function(result) {
asyncValue.resolve(result.getOutput());
})
.on('error', function(err) {
asyncValue.reject(err);
});
if (awaitContext.instances) {
awaitContext.instances.push(awaitInfo);
}
out.emit('await:clientReorder', awaitInfo);
} else {
out.flush(); // Flush everything up to this await instance
asyncOut = awaitInfo.out = out.beginAsync({
timeout: 0, // We will use our code for controlling timeout
name: name
});
}
} else if (clientReorder) {
// If the async fragment has finished synchronously then we still need to emit the `await:finish` event
out.emit('await:finish', awaitInfo);
}
};
|
| 1 2 | 1 | exports.isSupported = false; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 1 | function $af(id, after, doc, sourceEl, targetEl, docFragment, childNodes, i, len, af) { af = $af; if (after && !af[after]) { (af[(after = after + '$')] || (af[after] = [])).push(id); } else { doc = document; sourceEl = doc.getElementById('af' + id); targetEl = doc.getElementById('afph' + id); docFragment = doc.createDocumentFragment(); childNodes = sourceEl.childNodes; i = 0; len=childNodes.length; for (; i<len; i++) { docFragment.appendChild(childNodes.item(0)); } targetEl.parentNode.replaceChild(docFragment, targetEl); af[id] = 1; after = af[id + '$']; if (after) { i = 0; len = after.length; for (; i<len; i++) { af(after[i]); } } } // sourceEl.parentNode.removeChild(sourceEl); } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | 1 1 1 1 | var code;
var fs = require('fs');
exports.isSupported = true;
exports.getCode = function() {
if (!code) {
code = fs.readFileSync(require.resolve('./client-reorder-runtime.min.js'), 'utf8');
code = '<script type="text/javascript">' + code + '</script>';
}
return code;
};
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| cached-fragment-tag-transformer.js | 33.33% | (2 / 6) | 0% | (0 / 2) | 0% | (0 / 1) | 33.33% | (2 / 6) | |
| cached-fragment-tag.js | 4.35% | (1 / 23) | 0% | (0 / 10) | 0% | (0 / 4) | 4.35% | (1 / 23) | |
| default-cache-manager.js | 22.22% | (4 / 18) | 0% | (0 / 8) | 0% | (0 / 4) | 22.22% | (4 / 18) |
| 1 2 3 4 5 6 7 8 9 10 | 1 1 | var defaultCacheManagerPath = require.resolve('./default-cache-manager');
module.exports = function(el, context) {
if (!el.hasAttribute('cache-manager')) {
var requirePath = context.getRequirePath(defaultCacheManagerPath);
var defaultCacheManagerVar = context.importModule('__defaultCacheManager', requirePath);
el.setAttributeValue('cache-manager', defaultCacheManagerVar);
}
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 1 | 'use strict';
module.exports = {
render: function (input, out) {
var cacheKey = input.cacheKey;
if (!cacheKey) {
throw new Error('cache-key is required for <cached-fragment>');
}
var cacheManager = input.cacheManager;
var cache = cacheManager.getCache(input.cacheName || 'marko/cached-fragment');
var asyncOut = out.beginAsync();
cache.get(cacheKey,
{
builder: function(callback) {
var nestedOut = out.createOut();
if (input.renderBody) {
input.renderBody(nestedOut);
}
nestedOut
.on('error', callback)
.on('finish', function(result) {
callback(null, result.getOutput());
});
nestedOut.end();
}
}, function(err, result) {
if (err) {
return asyncOut.error(err);
}
if (result.$__cloneNode) {
var curChild = result.firstChild;
while(curChild) {
asyncOut.node(curChild.$__cloneNode());
curChild = curChild.nextSibling;
}
asyncOut.end();
} else {
asyncOut.end(result);
}
});
}
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 1 1 1 1 | var caches = {};
function createCache() {
var cache = {};
return {
get: function(cacheKey, options, callback) {
var value = cache[cacheKey];
if (value !== undefined) {
return callback(null, value);
}
var builder = options.builder;
builder(function(err, value) {
if (err) {
return callback(err);
}
if (value === undefined) {
value = null;
}
cache[cacheKey] = value;
callback(null, value);
});
}
};
}
var defaultCacheManager = {
getCache: function(cacheName) {
return caches[cacheName] || (caches[cacheName] = createCache());
}
};
module.exports = defaultCacheManager;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| assign-tag.js | 8.33% | (1 / 12) | 0% | (0 / 4) | 0% | (0 / 1) | 8.33% | (1 / 12) | |
| class-tag.js | 20% | (1 / 5) | 0% | (0 / 2) | 0% | (0 / 1) | 20% | (1 / 5) | |
| core-transformer.js | 6.84% | (8 / 117) | 0% | (0 / 36) | 6.67% | (1 / 15) | 6.84% | (8 / 117) | |
| else-if-tag.js | 6.25% | (1 / 16) | 0% | (0 / 4) | 0% | (0 / 1) | 6.25% | (1 / 16) | |
| else-tag.js | 4.76% | (1 / 21) | 0% | (0 / 10) | 0% | (0 / 1) | 4.76% | (1 / 21) | |
| for-tag.js | 15.38% | (2 / 13) | 0% | (0 / 4) | 0% | (0 / 1) | 15.38% | (2 / 13) | |
| if-tag.js | 6.67% | (1 / 15) | 0% | (0 / 4) | 0% | (0 / 1) | 6.67% | (1 / 15) | |
| import-tag.js | 13.64% | (3 / 22) | 0% | (0 / 8) | 0% | (0 / 1) | 13.64% | (3 / 22) | |
| include-html-tag-browser.js | 9.09% | (1 / 11) | 0% | (0 / 6) | 0% | (0 / 1) | 9.09% | (1 / 11) | |
| include-html-tag.js | 15.79% | (3 / 19) | 0% | (0 / 6) | 0% | (0 / 1) | 15.79% | (3 / 19) | |
| include-tag-transformer.js | 6.67% | (1 / 15) | 0% | (0 / 10) | 0% | (0 / 1) | 6.67% | (1 / 15) | |
| include-tag.js | 17.39% | (4 / 23) | 0% | (0 / 22) | 0% | (0 / 2) | 17.39% | (4 / 23) | |
| include-text-tag-browser.js | 9.09% | (1 / 11) | 0% | (0 / 6) | 0% | (0 / 1) | 9.09% | (1 / 11) | |
| include-text-tag.js | 15.79% | (3 / 19) | 0% | (0 / 6) | 0% | (0 / 1) | 15.79% | (3 / 19) | |
| invoke-tag.js | 7.14% | (1 / 14) | 0% | (0 / 4) | 0% | (0 / 1) | 7.14% | (1 / 14) | |
| macro-body-tag.js | 33.33% | (1 / 3) | 100% | (0 / 0) | 0% | (0 / 1) | 33.33% | (1 / 3) | |
| macro-tag.js | 5.26% | (1 / 19) | 0% | (0 / 8) | 0% | (0 / 1) | 5.26% | (1 / 19) | |
| marko-preserve-whitespace-tag.js | 50% | (1 / 2) | 100% | (0 / 0) | 0% | (0 / 1) | 50% | (1 / 2) | |
| static-tag.js | 11.11% | (1 / 9) | 0% | (0 / 4) | 0% | (0 / 1) | 11.11% | (1 / 9) | |
| unless-tag.js | 6.25% | (1 / 16) | 0% | (0 / 4) | 0% | (0 / 1) | 6.25% | (1 / 16) | |
| var-tag.js | 9.09% | (2 / 22) | 0% | (0 / 6) | 0% | (0 / 1) | 9.09% | (2 / 22) | |
| while-tag.js | 14.29% | (1 / 7) | 0% | (0 / 2) | 0% | (0 / 1) | 14.29% | (1 / 7) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 1 | module.exports = function codeGenerator(elNode, codegen) { var context = codegen.context; context.deprecate('The "<assign>" tag is deprecated. Please use "$ <js_code>" for JavaScript in the template. See: https://github.com/marko-js/marko/wiki/Deprecation:-var-assign-invoke-tags'); var attributes = elNode.attributes; if (!attributes) { codegen.addError('Invalid <assign> tag. Argument is missing. Example; <assign x=123 />'); return elNode; } var builder = codegen.builder; return attributes.map((attr) => { if (attr.value == null) { return builder.parseExpression(attr.name); } else { return builder.assignment(attr.name, attr.value); } }); }; |
| 1 2 3 4 5 6 7 8 | 1 | module.exports = function functionCodeGenerator(el, codegen) { if(el.parentNode.type !== 'TemplateRoot') { codegen.addError('class is a static tag and can only be declared at the template root'); } codegen.addStaticCode(codegen.builder.expression(el.tagString)); return null; }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | 1 1 1 11 11 11 1 1 | 'use strict';
var createLoopNode = require('./util/createLoopNode');
var coreAttrHandlers = [
[
'while', function(attr, node) {
var whileArgument = attr.argument;
if (!whileArgument) {
return false;
}
var whileNode = this.builder.whileStatement(whileArgument);
node.wrapWith(whileNode);
}
],
[
'for', function(attr, node) {
var forArgument = attr.argument;
if (!forArgument) {
return false;
}
var loopNode;
try {
loopNode = createLoopNode(forArgument, null, this.builder);
} catch(e) {
if (e.code === 'INVALID_FOR') {
this.addError(e.message);
return;
} else {
throw e;
}
}
//Surround the existing node with the newly created loop node
// NOTE: The loop node will be one of the following:
// ForEach, ForRange, ForEachProp or ForStatement
node.wrapWith(loopNode);
}
],
[
'if', function(attr, node) {
var ifArgument = attr.argument;
if (!ifArgument) {
return false;
}
var test;
try {
test = this.builder.parseExpression(ifArgument);
} catch(e) {
test = this.builder.literalFalse();
this.addError('Invalid expression for if statement:\n' + e.message);
}
var ifNode = this.builder.ifStatement(test);
//Surround the existing node with an "If" node
node.wrapWith(ifNode);
}
],
[
'unless', function(attr, node) {
var ifArgument = attr.argument;
if (!ifArgument) {
return false;
}
var test;
try {
test = this.builder.parseExpression(ifArgument);
} catch(e) {
test = this.builder.literalFalse();
this.addError('Invalid expression for unless statement:\n' + e.message);
}
test = this.builder.negate(test);
var ifNode = this.builder.ifStatement(test);
//Surround the existing node with an "if" node
node.wrapWith(ifNode);
}
],
[
'else-if', function(attr, node) {
var elseIfArgument = attr.argument;
if (!elseIfArgument) {
return false;
}
var test;
try {
test = this.builder.parseExpression(elseIfArgument);
} catch(e) {
test = this.builder.literalFalse();
this.addError('Invalid expression for else-if statement:\n' + e.message);
}
var elseIfNode = this.builder.elseIfStatement(test);
//Surround the existing node with an "ElseIf" node
node.wrapWith(elseIfNode);
}
],
[
'else', function(attr, node) {
var elseNode = this.builder.elseStatement();
//Surround the existing node with an "Else" node
node.wrapWith(elseNode);
}
],
[
'body-only-if', function(attr, node, el) {
var argument = attr.argument;
if (!argument) {
return false;
}
var test;
try {
test = this.builder.parseExpression(argument);
} catch(e) {
test = this.builder.literalFalse();
this.addError('Invalid expression for body-only-if statement:\n' + e.message);
}
el.setBodyOnlyIf(test);
}
],
[
'marko-preserve-whitespace', function(attr, node, el) {
el.setPreserveWhitespace(true);
}
],
[
'marko-init', function(attr, node, el) {
if (el.tagName !== 'script') {
this.addError('The "marko-init" attribute should only be used on the <script> tag');
return;
}
this.context.deprecate('The "marko-init" attribute is deprecated. Use the static tag instead. See https://github.com/marko-js/marko/issues/547');
var bodyText = el.bodyText;
el.noOutput = true;
this.context.addStaticCode(bodyText);
el.detach();
return null;
}
],
[
'template-helpers', function(attr, node, el) {
if (el.tagName !== 'script') {
this.addError('The "template-helpers" attribute should only be used on the <script> tag');
return;
}
this.context.deprecate('The "template-helpers" attribute is deprecated and will be removed in the next release candidate. Use the static tag instead. See https://github.com/marko-js/marko/issues/547');
var bodyText = el.bodyText;
el.noOutput = true;
this.context.addStaticCode(bodyText);
el.detach();
return null;
}
],
[
'include', function(attr, node, el) {
var context = this.context;
if (typeof attr.argument === 'string') {
if (attr.argument) {
var includeNode = context.createNodeForEl('include', null, attr.argument);
node.appendChild(includeNode);
} else {
context.addError(el, 'The include attribute must have an argument. For example: include("./target.marko") or include(data.renderBody)');
}
} else {
return false;
}
}
]
];
class AttributeTransformer {
constructor(context, el) {
this.context = context;
this.builder = context.builder;
this.el = el;
}
addError(message) {
this.context.addError({
node: this.el,
message: message
});
}
}
coreAttrHandlers.forEach(function(attrHandler) {
var name = attrHandler[0];
var func = attrHandler[1];
AttributeTransformer.prototype[name] = func;
});
var attributeTransformers = AttributeTransformer.prototype;
module.exports = function transform(el, context) {
el.removeAttribute('marko-body'); // This attribute is handled at parse time. We can just remove it now
var attributeTransfomer;
var node = el;
el.forEachAttribute((attr) => {
let attrName = attr.name;
if (!attrName) {
if (!node.addDynamicAttributes) {
context.addError(el, 'Node does not support the "attrs" attribute');
} else {
node.addDynamicAttributes(attr.value);
}
return;
}
var attrTransformerFunc = attributeTransformers[attrName];
if (attrTransformerFunc) {
if (!attributeTransfomer) {
attributeTransfomer = new AttributeTransformer(context, el);
}
var newNode = attributeTransfomer[attrName](attr, node, el);
if (newNode !== false) {
el.removeAttribute(attrName);
if (newNode !== undefined) {
if (newNode) {
newNode.pos = node.pos;
}
node = newNode;
}
}
}
});
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 1 | module.exports = function nodeFactory(el, context) { var argument = el.argument; var attributes = el.attributes; if (!argument) { context.addError('Invalid <else-if> tag. Argument is missing. Example; <if(foo === true)>'); return el; } if (attributes.length) { context.addError('Invalid <else-if> tag. Attributes not allowed.'); return el; } var test; try { test = context.builder.parseExpression(argument); } catch(e) { test = context.builder.literalFalse(); context.addError('Invalid expression for else-if statement:\n' + e.message); } var elseIfStatement = context.builder.elseIfStatement(test); return elseIfStatement; }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 1 | 'use strict'; module.exports = function nodeFactory(el, context) { var elseStatement = context.builder.elseStatement(); var argument = el.argument; if (argument) { context.addError(elseStatement, 'Invalid <else> tag. Argument is not allowed'); } if (el.hasAttribute('if')) { let ifAttr = el.getAttribute('if'); el.removeAttribute('if'); if (el.attributes.length) { context.addError(elseStatement, 'Invalid <else if> tag. Only the "if" attribute is allowed.'); return el; } var testExpression = ifAttr.argument; if (!testExpression) { context.addError(elseStatement, 'Invalid <else if> tag. Invalid "if" attribute. Expected: <else if(<test>)>'); return el; } var elseIfStatement = context.builder.elseIfStatement(testExpression); return elseIfStatement; } if (el.attributes.length) { context.addError(elseStatement, 'Invalid <else> tag. Attributes not allowed.'); return el; } return elseStatement; }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 1 1 | var createLoopNode = require('./util/createLoopNode');
module.exports = function codeGenerator(elNode, codegen) {
var argument = elNode.argument;
if (!argument) {
codegen.addError('Invalid <for> tag. Argument is missing. Example: <for(color in colors)>');
return elNode;
}
var builder = codegen.builder;
try {
var loopNode = createLoopNode(argument, elNode.body, builder);
return loopNode;
} catch(e) {
if (e.code === 'INVALID_FOR') {
codegen.addError(e.message);
} else {
throw e;
}
}
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 1 | module.exports = function nodeFactory(elNode, context) { var argument = elNode.argument; if (!argument) { context.addError('Invalid <if> tag. Argument is missing. Example; <if(foo === true)>'); return elNode; } var attributes = elNode.attributes; if (attributes.length) { context.addError('Invalid <if> tag. Attributes not allowed.'); return; } var test; try { test = context.builder.parseExpression(argument); } catch(e) { test = context.builder.literalFalse(); context.addError('Invalid expression for if statement:\n' + e.message); } return context.builder.ifStatement(test); }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 1 1 1 | var isValidJavaScriptVarName = require('../../compiler/util/isValidJavaScriptVarName');
var parseImport = require('./util/parseImport');
module.exports = function codeGenerator(el, codegen) {
var builder = codegen.builder;
var args = parseImport(el.tagString);
var vars = {};
args.forEach(arg => {
var varName = arg.name;
if (!isValidJavaScriptVarName(varName)) {
codegen.addError('Invalid JavaScript variable name: ' + varName, 'INVALID_VAR_NAME');
return;
}
if (arg.module) {
// needs to be require()'d
var result = builder.require(builder.literal(arg.value));
if (varName) {
// saves identifier
vars[varName] = codegen.addStaticVar(varName, result);
} else {
codegen.addStaticCode(result);
}
} else {
// ie: { bar } from "./bar"
var modIdentifier = vars[arg.value.object];
if (!modIdentifier) {
codegen.addError('Variable not found: ' + arg.value.object);
return;
}
codegen.addStaticVar(varName, builder.memberExpression(
modIdentifier,
builder.identifier(arg.value.property)
));
}
});
return [];
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 1 | 'use strict'; module.exports = function codeGenerator(el, codegen) { let argument = el.argument; if (!argument) { return; } let builder = codegen.builder; let pathExpression = builder.parseExpression(argument); if (pathExpression.type !== 'Literal' || typeof pathExpression.value !== 'string') { codegen.addError('Argument to the <include-text> tag should be a string value: <include-text("./foo.txt")/>'); return; } var path = pathExpression.value; return builder.text(builder.literal('<include-html> cannot be compiled in the browser (path="' + path + '")')); }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 1 1 1 | 'use strict';
var resolveFrom = require('resolve-from');
var fs = require('fs');
module.exports = function codeGenerator(el, codegen) {
let argument = el.argument;
if (!argument) {
return;
}
let builder = codegen.builder;
let pathExpression = builder.parseExpression(argument);
if (pathExpression.type !== 'Literal' || typeof pathExpression.value !== 'string') {
codegen.addError('Argument to the <include-html> tag should be a string value: <include-html("./foo.txt")/>');
return;
}
var path = pathExpression.value;
var dirname = codegen.context.dirname;
try {
path = resolveFrom(dirname, path);
} catch(e) {
codegen.addError('File not found: ' + path);
return;
}
var txt = fs.readFileSync(path, { encoding: 'utf8' });
return builder.text(builder.literal(txt), false /* do not escape since this is HTML*/);
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 1 | 'use strict'; module.exports = function(el, context) { let builder = context.builder; if (el.argument) { let args = el.argument && builder.parseJavaScriptArgs(el.argument); el.argument = null; let target = args[0]; let arg = args[1]; if (target.type === 'Literal') { target = context.importTemplate(target.value); } var includeProps = { _target: target }; if (arg) { includeProps._arg = arg; } el.addProps(includeProps); } else if (!el.hasProp('_target')) { context.addError(el, 'The <include(...)> tag must have an argument: <include("./target.marko")/> or <include(data.renderBody)/>'); } }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 1 1 1 1 | function doInclude(input, out, throwError) { var target = input._target; var arg = input._arg || input; if (target) { if (typeof target === 'function') { return target(out, arg), true; } else if (typeof target === 'string') { return (target && out.text(target)), true; } else if (typeof target === 'object') { if (target.renderBody) { return target.renderBody(out, arg), true; } else if (target.renderer) { return target.renderer(arg, out), true; } else if (target.render) { return target.render(arg, out), true; } else if (target.safeHTML) { return out.write(target.safeHTML), true; } else { if (throwError) { out.error('Invalid include target'); } } } } } function includeTag(input, out) { doInclude(input, out, true); } includeTag.$__doInclude = doInclude; module.exports = includeTag; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 1 | 'use strict'; module.exports = function codeGenerator(el, codegen) { let argument = el.argument; if (!argument) { return; } let builder = codegen.builder; let pathExpression = builder.parseExpression(argument); if (pathExpression.type !== 'Literal' || typeof pathExpression.value !== 'string') { codegen.addError('Argument to the <include-text> tag should be a string value: <include-text("./foo.txt")/>'); return; } var path = pathExpression.value; return builder.text(builder.literal('<include-text> cannot be compiled in the browser (path="' + path + '")')); }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 1 1 1 | 'use strict';
var resolveFrom = require('resolve-from');
var fs = require('fs');
module.exports = function codeGenerator(el, codegen) {
let argument = el.argument;
if (!argument) {
return;
}
let builder = codegen.builder;
let pathExpression = builder.parseExpression(argument);
if (pathExpression.type !== 'Literal' || typeof pathExpression.value !== 'string') {
codegen.addError('Argument to the <include-text> tag should be a string value: <include-text("./foo.txt")/>');
return;
}
var path = pathExpression.value;
var dirname = codegen.context.dirname;
try {
path = resolveFrom(dirname, path);
} catch(e) {
codegen.addError('File not found: ' + path);
return;
}
var txt = fs.readFileSync(path, { encoding: 'utf8' });
return builder.text(builder.literal(txt));
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 1 | module.exports = function codeGenerator(elNode, codegen) { var context = codegen.context; context.deprecate('The "<invoke>" tag is deprecated. Please use "$ <js_code>" for JavaScript in the template. See: https://github.com/marko-js/marko/wiki/Deprecation:-var-assign-invoke-tags'); var functionAttr = elNode.attributes[0]; if (!functionAttr) { codegen.addError('Invalid <invoke> tag. Missing function attribute. Expected: <invoke console.log("Hello World")'); return; } var arg = functionAttr.argument; if (arg === undefined) { codegen.addError('Invalid <invoke> tag. Missing function arguments. Expected: <invoke console.log("Hello World")'); return; } var functionName = functionAttr.name; var functionCallExpression = functionName + '(' + arg + ')'; return codegen.builder.parseExpression(functionCallExpression); }; |
| 1 2 3 4 5 6 7 8 | 1 | module.exports = function codeGenerator(elNode, codegen) { var builder = codegen.builder; return builder.ifStatement(builder.identifier('renderBody'), [ builder.functionCall('renderBody', ['out']) ]); }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 1 | module.exports = function nodeFactory(elNode, context) { var attributes = elNode.attributes; var defAttr = attributes[0]; if(!defAttr || defAttr.value !== undefined) { context.addError(elNode, 'The <macro> tag must contain a name as its first attribute, example: <macro greeting()>'); return elNode; } var body = elNode.body; var macroName = defAttr.name; if (context.isMacro(macroName)) { context.addError(elNode, `<macro> tag with duplicate name of "${macroName}" found.`); return elNode; } var argument = defAttr.argument; var params; if (argument) { params = argument.split(/\s*,\s*/); } else { params = []; } var builder = context.builder; context.registerMacro(macroName, params); return builder.macro(macroName, params, body); }; |
| 1 2 3 4 | 1 | module.exports = function codeGenerator(elNode, codegen) { return elNode.body; }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 1 | module.exports = function functionCodeGenerator(el, codegen) { if(el.parentNode.type !== 'TemplateRoot') { codegen.addError('static is a static tag and can only be declared at the template root'); } var code = el.tagString.replace(/^static\s*/, '').trim(); if(code[0] === '{') { var statements = code.slice(1, -1); codegen.addStaticCode(codegen.builder.code(statements)); } else { codegen.addStaticCode(codegen.builder.expression(code)); } return null; }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 1 | module.exports = function nodeFactory(elNode, context) { var argument = elNode.argument; if (!argument) { context.addError('Invalid <unless> tag. Argument is missing. Example; <unless(foo === true)>'); return elNode; } var attributes = elNode.attributes; if (attributes.length) { context.addError('Invalid <unless> tag. Attributes not allowed.'); return; } var builder = context.builder; var test; try { test = builder.parseExpression(argument); } catch(e) { test = builder.literalFalse(); context.addError('Invalid expression for unless statement:\n' + e.message); } return context.builder.ifStatement(builder.negate(test)); }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 1 1 | var isValidJavaScriptVarName = require('../../compiler/util/isValidJavaScriptVarName');
module.exports = function nodeFactory(el, context) {
context.deprecate('The "<var>" tag is deprecated. Please use "$ <js_code>" for JavaScript in the template. See: https://github.com/marko-js/marko/wiki/Deprecation:-var-assign-invoke-tags');
var vars;
try {
vars = context.builder.parseStatement(el.tagString);
} catch(e) {}
if (vars) {
return vars;
}
var builder = context.builder;
var hasError = false;
var declarations = el.attributes.map((attr) => {
var varName = attr.name;
if (!isValidJavaScriptVarName(varName)) {
context.addError('Invalid JavaScript variable name: ' + varName, 'INVALID_VAR_NAME');
hasError = true;
return;
}
var id = builder.identifier(varName);
var init = attr.value;
return {
id: id,
init
};
});
if (hasError) {
return el;
}
return context.builder.vars(declarations);
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 | 1 | module.exports = function codeGenerator(elNode, codegen) { var argument = elNode.argument; if (!argument) { codegen.addError('Invalid <while> tag. Argument is missing. Example: <while(i < 4)>'); return elNode; } var builder = codegen.builder; return builder.whileStatement(builder.parseExpression(argument), elNode.body); }; |
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| createLoopNode.js | 21.43% | (3 / 14) | 0% | (0 / 8) | 0% | (0 / 1) | 21.43% | (3 / 14) | |
| parseFor.js | 7.69% | (14 / 182) | 0% | (0 / 121) | 0% | (0 / 8) | 7.69% | (14 / 182) | |
| parseImport.js | 14.29% | (5 / 35) | 0% | (0 / 12) | 0% | (0 / 5) | 15.15% | (5 / 33) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 1 1 1 | var parseFor = require('./parseFor');
function createLoopNode(str, body, builder) {
var forDef = parseFor(str);
forDef.body = body;
if (forDef.loopType === 'ForEach') {
return builder.forEach(forDef);
} else if (forDef.loopType === 'ForRange') {
return builder.forRange(forDef);
} else if (forDef.loopType === 'ForEachProp') {
return builder.forEachProp(forDef);
} else if (forDef.loopType === 'For') {
return builder.forStatement(forDef);
} else {
throw new Error('Unsupported loop type: ' + forDef.loopType);
}
}
module.exports = createLoopNode;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var removeComments = require('../../../compiler/util/removeComments');
var compiler = require('../../../compiler');
var integerRegExp = /^-?\d+$/;
var numberRegExp = /^-?(?:\d+|\d+\.\d*|\d*\.\d+|\d+\.\d+)$/;
var tokenizer = require('../../../compiler/util/tokenizer').create([
{
name: 'stringDouble',
pattern: /"(?:[^"]|\\")*"/,
},
{
name: 'stringSingle',
pattern: /'(?:[^']|\\')*'/
},
{
name: 'in',
pattern: /\s+in\s+/,
},
{
name: 'from',
pattern: /\s+from\s+/
},
{
name: 'to',
pattern: /\s+to\s+/,
},
{
name: 'step',
pattern: /\s+step\s+/,
},
{
name: 'semicolon',
pattern: /[;]/,
},
{
name: 'separator',
pattern: /separator=/
},
{
name: 'status-var',
pattern: /status\-var=/
},
{
name: 'iterator',
pattern: /iterator=/
},
{
name: 'pipe',
pattern: /\s+\|\s+/
},
{
name: 'groupOpen',
pattern: /[\{\(\[]/
},
{
name: 'groupClose',
pattern: /[\}\)\]]/
},
{
name: 'array',
pattern: /array/
}
]);
var inRegExp = /^\s*([$A-Z_][0-9A-Z_$]*)(?:\s*,\s*([$A-Z_][0-9A-Z_$]*))?\s+in\s+/i;
function throwError(message) {
var error = new Error(message);
error.code = 'INVALID_FOR';
throw error;
}
function buildIdentifier(name, errorMessage) {
try {
return compiler.builder.identifier(name);
} catch(e) {
throwError(errorMessage + ': ' + e.message);
}
}
function parseExpression(str, errorMessage) {
try {
return compiler.builder.parseExpression(str);
} catch(e) {
throwError(errorMessage + ': ' + e.message);
}
}
function parseStatement(str, errorMessage) {
try {
return compiler.builder.parseStatement(str);
} catch(e) {
throwError(errorMessage + ': ' + e.message);
}
}
function createNumberExpression(str, errorMessage) {
if (str == null) {
return null;
}
if (integerRegExp.test(str)) {
return compiler.builder.literal(parseInt(str, 10));
} else if (numberRegExp.test(str)) {
return compiler.builder.literal(parseFloat(str));
} else {
return parseExpression(str, errorMessage);
}
}
/**
* Parses a for loop string in the following forms:
*
* <varName> in <expression>
* <varName> in <expression> | status-var=<varName> separator=<expression>
* <varName> from <expression> to <expression>
* <varName> from <expression> to <expression> step <expression>
* <init>; <test>; <update>
*/
module.exports = function(str) {
str = removeComments(str);
let depth = 0;
var prevToken;
var loopType;
var pipeFound = false;
var varName;
var nameVarName;
var valueVarName;
var inExpression;
var statusVarName;
var separatorExpression;
var fromExpression;
var toExpression;
var stepExpression;
var iteratorExpression;
var isArray;
var forInit;
var forTest;
var forUpdate;
var inRegExpMatches = inRegExp.exec(str);
if (inRegExpMatches) {
if (inRegExpMatches[1] && inRegExpMatches[2]) {
loopType = 'ForEachProp';
nameVarName = inRegExpMatches[1];
valueVarName = inRegExpMatches[2];
} else {
loopType = 'ForEach';
varName = inRegExpMatches[1];
}
str = ' in ' + str.substring(inRegExpMatches[0].length);
}
function finishVarName(end) {
varName = str.substring(0, end).trim();
}
function finishPrevPart(end) {
if (!prevToken) {
return;
}
var start = prevToken.end;
var part = str.substring(start, end).trim();
switch(prevToken.name) {
case 'from':
fromExpression = part;
break;
case 'to':
toExpression = part;
break;
case 'in':
inExpression = part;
break;
case 'step':
stepExpression = part;
break;
case 'status-var':
statusVarName = part;
break;
case 'separator':
separatorExpression = part;
break;
case 'iterator':
iteratorExpression = part;
break;
case 'array':
isArray = true;
break;
case 'pipe':
if (part.length !== 0) {
throwError('Unexpected input: ' + part);
return;
}
break;
}
}
tokenizer.forEachToken(str, (token) => {
switch(token.name) {
case 'groupOpen':
depth++;
break;
case 'groupClose':
depth--;
break;
case 'in':
if (depth === 0) {
prevToken = token;
}
break;
case 'from':
if (depth === 0 && !loopType) {
loopType = 'ForRange';
finishVarName(token.start);
prevToken = token;
}
break;
case 'to':
if (depth === 0 && prevToken && prevToken.name === 'from') {
finishPrevPart(token.start);
prevToken = token;
}
break;
case 'step':
if (depth === 0 && prevToken && prevToken.name === 'to') {
finishPrevPart(token.start);
prevToken = token;
}
break;
case 'semicolon':
if (depth === 0) {
loopType = 'For';
if (forInit == null) {
forInit = str.substring(0, token.start);
} else if (forTest == null) {
forTest = str.substring(prevToken.end, token.start);
forUpdate = str.substring(token.end);
} else {
throwError('Invalid native for loop. Expected format: <init>; <test>; <update>');
}
prevToken = token;
}
break;
case 'pipe':
if (depth === 0) {
pipeFound = true;
finishPrevPart(token.start);
prevToken = token;
}
break;
case 'status-var':
if (depth === 0 && pipeFound && str.charAt(token.start-1) === ' ') {
finishPrevPart(token.start);
prevToken = token;
}
break;
case 'separator':
if (depth === 0 && pipeFound && str.charAt(token.start-1) === ' ') {
finishPrevPart(token.start);
prevToken = token;
}
break;
case 'iterator':
if (depth === 0 && pipeFound && str.charAt(token.start-1) === ' ') {
finishPrevPart(token.start);
prevToken = token;
}
break;
case 'array':
if (depth === 0 && pipeFound && str.charAt(token.start-1) === ' ') {
finishPrevPart(token.start);
prevToken = token;
}
break;
}
});
finishPrevPart(str.length);
if (inExpression) {
inExpression = parseExpression(inExpression, 'Invalid "in" expression');
}
if (separatorExpression) {
separatorExpression = parseExpression(separatorExpression, 'Invalid "separator" expression');
}
if (iteratorExpression) {
iteratorExpression = parseExpression(iteratorExpression, 'Invalid "iterator" expression');
}
if (fromExpression) {
fromExpression = createNumberExpression(fromExpression, 'Invalid "from" expression');
}
if (toExpression) {
toExpression = createNumberExpression(toExpression, 'Invalid "to" expression');
}
if (stepExpression) {
stepExpression = createNumberExpression(stepExpression, 'Invalid "step" expression');
}
if (varName != null) {
varName = buildIdentifier(varName, 'Invalid variable name');
}
if (nameVarName) {
nameVarName = buildIdentifier(nameVarName, 'Invalid name variable');
}
if (valueVarName) {
valueVarName = buildIdentifier(valueVarName, 'Invalid value variable');
}
if (statusVarName) {
statusVarName = parseExpression(statusVarName, 'Invalid status-var option');
if (statusVarName.type === 'Literal') {
statusVarName = compiler.builder.identifier(statusVarName.value);
} else if (statusVarName.type !== 'Identifier') {
throwError('Invalid status-var option');
}
}
if (forInit) {
forInit = parseStatement(forInit, 'Invalid for loop init');
}
if (forTest) {
forTest = parseExpression(forTest, 'Invalid for loop test');
}
if (forUpdate) {
forUpdate = parseExpression(forUpdate, 'Invalid for loop update');
}
// No more tokens... now we need to sort out what happened
if (loopType === 'ForEach') {
return {
'loopType': loopType,
'varName': varName,
'in': inExpression,
'separator': separatorExpression,
'statusVarName': statusVarName,
'iterator': iteratorExpression,
'isArray': isArray
};
} else if (loopType === 'ForEachProp') {
return {
'loopType': loopType,
'nameVarName': nameVarName,
'valueVarName': valueVarName,
'in': inExpression,
'separator': separatorExpression,
'statusVarName': statusVarName
};
} else if (loopType === 'ForRange') {
return {
'loopType': loopType,
'varName': varName,
'from': fromExpression,
'to': toExpression,
'step': stepExpression
};
} else if (loopType === 'For') {
if (forTest == null) {
throwError('Invalid native for loop. Expected format: <init>; <test>; <update>');
}
return {
'loopType': loopType,
'init': forInit,
'test': forTest,
'update': forUpdate
};
} else {
throwError('Invalid for loop');
}
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | 1 1 1 1 1 | "use strict"; function getSpecifiers(importDeclaration) { var match = /^(.+)\bfrom\s*(("|')(.*?)("|'))$/.exec(importDeclaration); if(!match) { return { moduleSpecifier: importDeclaration.replace(/\"|\'/g, "").trim() }; } return { importSpecifierSet: match[1].trim(), moduleSpecifier: match[4].trim() }; } function getImportSpecifierGroups(importSpecifierSet) { var defaultImport = importSpecifierSet; var decomposedImports = /(?:,\s*)?{(.*)}$/.exec(importSpecifierSet) || []; if(decomposedImports.length) { defaultImport = defaultImport.replace(decomposedImports[0], ''); decomposedImports = decomposedImports[1].split(',').map(specifier => specifier.trim()); } return { defaultImport: defaultImport, decomposedImports: decomposedImports }; } function getVariableName(moduleSpecifier) { var withoutPath = /([^\/\\]+)$/.exec(moduleSpecifier)[1]; var withoutExtension = withoutPath.replace(/\.[a-z0-9]+$/i, ''); return withoutExtension.replace(/[^a-z0-9]+([a-z])/gi, (_, p1) => p1.toUpperCase())+'_module'; } function getNames(importSpecifier) { var names = importSpecifier.split(/\bas\b/); if (names.length == 1) { names[1] = names[0]; } return { exported: names[0].trim(), local: names[1].trim() }; } module.exports = function importToAssignments(tagString) { var importDeclaration = tagString.replace(/^import/, '').trim(); var specifiers = getSpecifiers(importDeclaration); var importSpecifierSet = specifiers.importSpecifierSet; var moduleSpecifier = specifiers.moduleSpecifier; if(!importSpecifierSet) { return [ { module: true, value: moduleSpecifier } ]; } var importGroups = getImportSpecifierGroups(importSpecifierSet); var rootVariable = getNames(importGroups.defaultImport).local || getVariableName(moduleSpecifier); var specifierList = importGroups.decomposedImports.map(getNames).map(names => { return { name: names.local, value: { object: rootVariable, property: names.exported } }; }); return [{ name: rootVariable, value: moduleSpecifier, module: true }].concat(specifierList) ; }; |
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| html-comment-tag.js | 16.67% | (1 / 6) | 0% | (0 / 4) | 0% | (0 / 1) | 16.67% | (1 / 6) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | 1 | 'use strict'; module.exports = function render(input, out) { if (out.write) { out.write('<!--'); if (input.renderBody) { input.renderBody(out); } out.write('-->'); } }; |
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| placeholder-tag.js | 11.11% | (2 / 18) | 0% | (0 / 6) | 0% | (0 / 1) | 11.11% | (2 / 18) | |
| put-tag.js | 9.09% | (1 / 11) | 0% | (0 / 2) | 0% | (0 / 1) | 9.09% | (1 / 11) | |
| use-tag.js | 11.11% | (1 / 9) | 0% | (0 / 2) | 0% | (0 / 1) | 11.11% | (1 / 9) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 1 1 | var removeDashes = require('../../compiler/util/removeDashes');
module.exports = function render(oldNode, context) {
context.deprecate('The <layout-placeholder> tag is deprecated. Please use <include> instead. See: https://github.com/marko-js/marko/issues/452');
var name = oldNode.getAttributeValue('name');
var builder = context.builder;
var content;
if (name.type === 'Literal' && typeof name.value === 'string') {
content = builder.memberExpression('input', removeDashes(name.value));
} else {
content = builder.memberExpression('input', name, true);
}
var newNode = context.createNodeForEl('include');
newNode.addProps({ _target:content });
if (oldNode.firstChild) {
var ifNode = builder.ifStatement(content, [newNode]);
var elseNode = builder.elseStatement();
oldNode.moveChildrenTo(elseNode);
oldNode.replaceWith(ifNode);
ifNode.insertSiblingAfter(elseNode);
} else {
oldNode.replaceWith(newNode);
}
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 1 | module.exports = function render(oldNode, context) { context.deprecate('The <layout-put> tag is deprecated. Please use <include> instead. See: https://github.com/marko-js/marko/issues/452'); var name = oldNode.getAttributeValue('into').value; var value = oldNode.getAttributeValue('value'); oldNode.removeAttribute('into'); oldNode.removeAttribute('value'); var newNode = context.createNodeForEl('@'+name, oldNode.getAttributes()); if (value) { newNode.appendChild(context.builder.text(value)); } oldNode.moveChildrenTo(newNode); oldNode.replaceWith(newNode); }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 1 | 'use strict'; module.exports = function transform(oldNode, context) { var argument = oldNode.argument; if (!argument) { context.addError('Invalid <layout-use> tag. Expected: <layout-use(template[, data]) ...>'); return; } context.deprecate('The <layout-use> tag is deprecated. Please use <include> instead. See: https://github.com/marko-js/marko/issues/452'); var newNode = context.createNodeForEl('include', oldNode.getAttributes(), argument); oldNode.moveChildrenTo(newNode); oldNode.replaceWith(newNode); }; |